Enforce cargo clippy strict mode

This commit is contained in:
Austen Adler 2021-05-19 20:08:50 -04:00
parent 9f0ca9d276
commit 17e74b0f52
6 changed files with 96 additions and 82 deletions

View File

@ -1,19 +1,19 @@
pub mod constants;
pub mod errors; pub mod errors;
pub mod operations; pub mod operations;
pub mod types;
use confy::{load, store}; use confy::{load, store};
use constants::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
RegisterState,
};
use errors::{CalculatorError, CalculatorResult}; use errors::{CalculatorError, CalculatorResult};
use operations::{CalculatorOperation, CalculatorStateChange, MacroState, OpArgs}; use operations::{CalculatorOperation, CalculatorStateChange, MacroState, OpArgs};
use serde::ser::Serializer; use serde::ser::Serializer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::collections::{HashSet, VecDeque}; use std::collections::{HashSet, VecDeque};
use types::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
RegisterState,
};
const MAX_PRECISION: usize = 20; const MAX_PRECISION: usize = 20;
const APP_NAME: &str = "rpn_rs"; const APP_NAME: &str = "rpn_rs";
@ -66,7 +66,7 @@ where
impl Default for Calculator { impl Default for Calculator {
fn default() -> Self { fn default() -> Self {
Calculator { Self {
l: String::new(), l: String::new(),
redo_buf: vec![], redo_buf: vec![],
undo_buf: vec![], undo_buf: vec![],
@ -136,13 +136,15 @@ impl Calculator {
} }
} }
pub fn load_config() -> CalculatorResult<Calculator> { pub fn load_config() -> CalculatorResult<Self> {
load(APP_NAME).map_err(|e| CalculatorError::LoadError(Some(e))) load(APP_NAME).map_err(|e| CalculatorError::LoadError(Some(e)))
} }
pub fn save_config(&self) -> CalculatorResult<()> { pub fn save_config(&self) -> CalculatorResult<()> {
store(APP_NAME, self).map_err(|e| CalculatorError::SaveError(Some(e))) store(APP_NAME, self).map_err(|e| CalculatorError::SaveError(Some(e)))
} }
// This maps chars to operations. Not sure I can make this shorter
#[allow(clippy::too_many_lines)]
pub fn take_input(&mut self, c: char) -> CalculatorResult<()> { pub fn take_input(&mut self, c: char) -> CalculatorResult<()> {
match &self.state { match &self.state {
CalculatorState::Normal => match c { CalculatorState::Normal => match c {
@ -274,12 +276,8 @@ impl Calculator {
} }
} }
'S' => { 'S' => {
let precision = self.checked_get(0)? as usize;
if precision > MAX_PRECISION {
return Err(CalculatorError::PrecisionTooHigh);
}
self.display_mode = CalculatorDisplayMode::Scientific { self.display_mode = CalculatorDisplayMode::Scientific {
precision: self.pop_usize()?, precision: self.pop_precision()?,
} }
} }
'e' => { 'e' => {
@ -288,12 +286,8 @@ impl Calculator {
} }
} }
'E' => { 'E' => {
let precision = self.checked_get(0)? as usize;
if precision > MAX_PRECISION {
return Err(CalculatorError::PrecisionTooHigh);
}
self.display_mode = CalculatorDisplayMode::Engineering { self.display_mode = CalculatorDisplayMode::Engineering {
precision: self.pop_usize()?, precision: self.pop_precision()?,
} }
} }
'f' => { 'f' => {
@ -303,7 +297,7 @@ impl Calculator {
} }
'F' => { 'F' => {
self.display_mode = CalculatorDisplayMode::Fixed { self.display_mode = CalculatorDisplayMode::Fixed {
precision: self.pop_usize()?, precision: self.pop_precision()?,
} }
} }
'w' => self.save_on_close = false, 'w' => self.save_on_close = false,
@ -405,24 +399,36 @@ impl Calculator {
push: OpArgs::Unary(f), push: OpArgs::Unary(f),
}) })
} }
pub fn pop(&mut self) -> CalculatorResult<f64> { pub fn peek(&mut self) -> CalculatorResult<f64> {
self.flush_l()?; self.flush_l()?;
let f = self.checked_get(0)?; self.checked_get(0)
}
pub fn pop(&mut self) -> CalculatorResult<f64> {
let f = self.peek()?;
self.direct_state_change(CalculatorStateChange { self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(f), pop: OpArgs::Unary(f),
push: OpArgs::None, push: OpArgs::None,
})?; })?;
Ok(f) Ok(f)
} }
pub fn pop_usize(&mut self) -> CalculatorResult<usize> { pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
self.flush_l()?; let f = self.peek()?;
let f = self.checked_get(0)?; // Ensure this can be cast to a usize
let ret = f as usize; if !f.is_finite() || f.is_sign_negative() {
return Err(CalculatorError::ArithmeticError);
}
#[allow(clippy::cast_sign_loss)]
let u = f as usize;
if u > MAX_PRECISION {
return Err(CalculatorError::PrecisionTooHigh);
}
self.direct_state_change(CalculatorStateChange { self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(f), pop: OpArgs::Unary(f),
push: OpArgs::None, push: OpArgs::None,
})?; })?;
Ok(ret) Ok(u)
} }
pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> { pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> {
// Dup is special -- don't actually run it if l needs to be flushed // Dup is special -- don't actually run it if l needs to be flushed
@ -441,7 +447,7 @@ impl Calculator {
} }
CalculatorOperation::Negate => self.unary_op(|a| OpArgs::Unary(-a)), CalculatorOperation::Negate => self.unary_op(|a| OpArgs::Unary(-a)),
CalculatorOperation::AbsoluteValue => self.unary_op(|a| OpArgs::Unary(a.abs())), CalculatorOperation::AbsoluteValue => self.unary_op(|a| OpArgs::Unary(a.abs())),
CalculatorOperation::Inverse => self.unary_op(|a| OpArgs::Unary(1.0 / a)), CalculatorOperation::Inverse => self.unary_op(|a| OpArgs::Unary(a.recip())),
CalculatorOperation::Modulo => self.binary_op(|[a, b]| OpArgs::Unary(b % a)), CalculatorOperation::Modulo => self.binary_op(|[a, b]| OpArgs::Unary(b % a)),
//CalculatorOperation::Remainder => self.binary_op(|[a, b]| OpArgs::Unary(b.rem_euclid(a))), //CalculatorOperation::Remainder => self.binary_op(|[a, b]| OpArgs::Unary(b.rem_euclid(a))),
CalculatorOperation::Dup => self.unary_op(|a| OpArgs::Binary([a, a])), CalculatorOperation::Dup => self.unary_op(|a| OpArgs::Binary([a, a])),
@ -493,7 +499,7 @@ impl Calculator {
CalculatorOperation::Log => self.unary_op(|a| OpArgs::Unary(a.log10())), CalculatorOperation::Log => self.unary_op(|a| OpArgs::Unary(a.log10())),
CalculatorOperation::Ln => self.unary_op(|a| OpArgs::Unary(a.ln())), CalculatorOperation::Ln => self.unary_op(|a| OpArgs::Unary(a.ln())),
CalculatorOperation::Pow => self.binary_op(|[a, b]| OpArgs::Unary(b.powf(a))), CalculatorOperation::Pow => self.binary_op(|[a, b]| OpArgs::Unary(b.powf(a))),
CalculatorOperation::E => self.binary_op(|[a, b]| OpArgs::Unary(b * 10.0f64.powf(a))), CalculatorOperation::E => self.binary_op(|[a, b]| OpArgs::Unary(b * 10.0_f64.powf(a))),
CalculatorOperation::Undo => return self.history_op(false), CalculatorOperation::Undo => return self.history_op(false),
CalculatorOperation::Redo => return self.history_op(true), CalculatorOperation::Redo => return self.history_op(true),
// Macros are a no-op operator; need to insert for undo/redo // Macros are a no-op operator; need to insert for undo/redo

View File

@ -27,30 +27,30 @@ impl error::Error for CalculatorError {}
impl fmt::Display for CalculatorError { impl fmt::Display for CalculatorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
CalculatorError::ArithmeticError => write!(f, "Arithmetic Error"), Self::ArithmeticError => write!(f, "Arithmetic Error"),
CalculatorError::NotEnoughStackEntries => write!(f, "Not enough items in the stack"), Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
CalculatorError::CorruptStateChange(msg) => { Self::CorruptStateChange(msg) => {
write!(f, "Corrupt state change: {}", msg) write!(f, "Corrupt state change: {}", msg)
} }
CalculatorError::EmptyHistory(msg) => write!(f, "No history to {}", msg), Self::EmptyHistory(msg) => write!(f, "No history to {}", msg),
CalculatorError::NoSuchOperator(c) => write!(f, "No such operator '{}'", c), Self::NoSuchOperator(c) => write!(f, "No such operator '{}'", c),
CalculatorError::NoSuchConstant(c) => write!(f, "No such constant '{}'", c), Self::NoSuchConstant(c) => write!(f, "No such constant '{}'", c),
CalculatorError::NoSuchRegister(c) => write!(f, "No such register '{}'", c), Self::NoSuchRegister(c) => write!(f, "No such register '{}'", c),
CalculatorError::NoSuchMacro(c) => write!(f, "No such macro '{}'", c), Self::NoSuchMacro(c) => write!(f, "No such macro '{}'", c),
CalculatorError::NoSuchSetting(c) => write!(f, "No such setting '{}'", c), Self::NoSuchSetting(c) => write!(f, "No such setting '{}'", c),
CalculatorError::RecursiveMacro(c) => write!(f, "Recursive macro '{}'", c), Self::RecursiveMacro(c) => write!(f, "Recursive macro '{}'", c),
CalculatorError::ParseError => write!(f, "Parse error"), Self::ParseError => write!(f, "Parse error"),
CalculatorError::PrecisionTooHigh => write!(f, "Precision too high"), Self::PrecisionTooHigh => write!(f, "Precision too high"),
CalculatorError::SaveError(None) => write!(f, "Could not save"), Self::SaveError(None) => write!(f, "Could not save"),
CalculatorError::SaveError(Some(ConfyError::SerializeTomlError(e))) => { Self::SaveError(Some(ConfyError::SerializeTomlError(e))) => {
write!(f, "Save serialization error: {}", e) write!(f, "Save serialization error: {}", e)
} }
CalculatorError::SaveError(Some(e)) => write!(f, "Could not save: {}", e), Self::SaveError(Some(e)) => write!(f, "Could not save: {}", e),
CalculatorError::LoadError(None) => write!(f, "Could not load"), Self::LoadError(None) => write!(f, "Could not load"),
CalculatorError::LoadError(Some(ConfyError::SerializeTomlError(e))) => { Self::LoadError(Some(ConfyError::SerializeTomlError(e))) => {
write!(f, "Load serialization error: {}", e) write!(f, "Load serialization error: {}", e)
} }
CalculatorError::LoadError(Some(e)) => write!(f, "Could not load: {}", e), Self::LoadError(Some(e)) => write!(f, "Could not load: {}", e),
} }
} }
} }

View File

@ -19,7 +19,7 @@ pub enum CalculatorState {
impl Default for CalculatorState { impl Default for CalculatorState {
fn default() -> Self { fn default() -> Self {
CalculatorState::Normal Self::Normal
} }
} }
@ -53,16 +53,16 @@ pub enum CalculatorAngleMode {
impl Default for CalculatorAngleMode { impl Default for CalculatorAngleMode {
fn default() -> Self { fn default() -> Self {
CalculatorAngleMode::Degrees Self::Degrees
} }
} }
impl fmt::Display for CalculatorAngleMode { impl fmt::Display for CalculatorAngleMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
CalculatorAngleMode::Degrees => write!(f, "DEG"), Self::Degrees => write!(f, "DEG"),
CalculatorAngleMode::Radians => write!(f, "RAD"), Self::Radians => write!(f, "RAD"),
CalculatorAngleMode::Grads => write!(f, "GRD"), Self::Grads => write!(f, "GRD"),
} }
} }
} }
@ -81,18 +81,18 @@ pub enum CalculatorDisplayMode {
impl fmt::Display for CalculatorDisplayMode { impl fmt::Display for CalculatorDisplayMode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
CalculatorDisplayMode::Default => write!(f, "DEF"), Self::Default => write!(f, "DEF"),
CalculatorDisplayMode::Separated { separator } => write!(f, "SEP({})", separator), Self::Separated { separator } => write!(f, "SEP({})", separator),
CalculatorDisplayMode::Scientific { precision } => write!(f, "SCI({})", precision), Self::Scientific { precision } => write!(f, "SCI({})", precision),
CalculatorDisplayMode::Engineering { precision } => write!(f, "ENG({})", precision), Self::Engineering { precision } => write!(f, "ENG({})", precision),
CalculatorDisplayMode::Fixed { precision } => write!(f, "FIX({})", precision), Self::Fixed { precision } => write!(f, "FIX({})", precision),
} }
} }
} }
impl Default for CalculatorDisplayMode { impl Default for CalculatorDisplayMode {
fn default() -> Self { fn default() -> Self {
CalculatorDisplayMode::Default Self::Default
} }
} }
@ -104,15 +104,15 @@ pub enum CalculatorAlignment {
impl Default for CalculatorAlignment { impl Default for CalculatorAlignment {
fn default() -> Self { fn default() -> Self {
CalculatorAlignment::Left Self::Left
} }
} }
impl fmt::Display for CalculatorAlignment { impl fmt::Display for CalculatorAlignment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
CalculatorAlignment::Left => write!(f, "L"), Self::Left => write!(f, "L"),
CalculatorAlignment::Right => write!(f, "R"), Self::Right => write!(f, "R"),
} }
} }
} }

View File

@ -19,7 +19,7 @@ pub struct Events {
} }
impl Events { impl Events {
pub fn new(tick_rate: u64) -> Events { pub fn new(tick_rate: u64) -> Self {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
let tick_handle = { let tick_handle = {
let tx = tx.clone(); let tx = tx.clone();
@ -44,14 +44,14 @@ impl Events {
} }
}) })
}; };
Events { Self {
tx, tx,
rx, rx,
tick_handle, tick_handle,
} }
} }
/// Returns a chain of the next element (blocking) and a TryIter of everything after it. /// Returns a chain of the next element (blocking) and a `TryIter` of everything after it.
/// Useful for reading a single Iterator of all elements once after blocking, so there are not too many UI redraws. /// Useful for reading a single Iterator of all elements once after blocking, so there are not too many UI redraws.
pub fn blocking_iter( pub fn blocking_iter(
&self, &self,

View File

@ -2,13 +2,11 @@
pub fn scientific(f: f64, precision: usize) -> String { pub fn scientific(f: f64, precision: usize) -> String {
let mut ret = format!("{:.precision$E}", f, precision = precision); let mut ret = format!("{:.precision$E}", f, precision = precision);
let exp = ret.split_off(ret.find('E').unwrap_or(0)); let exp = ret.split_off(ret.find('E').unwrap_or(0));
let (exp_sign, exp) = if let Some(stripped) = exp.strip_prefix("E-") { let (exp_sign, exp) = exp
('-', stripped) .strip_prefix("E-")
} else { .map_or_else(|| ('+', &exp[1..]), |stripped| ('-', stripped));
('+', &exp[1..])
};
let sign = if !ret.starts_with('-') { " " } else { "" }; let sign = if ret.starts_with('-') { "" } else { " " };
format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2) format!("{}{} E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2)
} }
@ -48,9 +46,9 @@ pub fn engineering(f: f64, precision: usize) -> String {
// Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit) // Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit)
// Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10 // Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10
let whole = &num_str[0..(num_whole_digits + 1)]; let whole = &num_str[0..=num_whole_digits];
// Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2 // Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2
let decimal = &num_str[(num_whole_digits + 1)..(precision + num_whole_digits + 1)]; let decimal = &num_str[(num_whole_digits + 1)..=(precision + num_whole_digits)];
// Right align whole portion, always have decimal point // Right align whole portion, always have decimal point
format!( format!(
"{: >4}.{} E{}{:0>pad$}", "{: >4}.{} E{}{:0>pad$}",

View File

@ -1,10 +1,16 @@
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
// This is intended behavior
#![allow(clippy::cast_possible_truncation)]
// Cannot fix this, so don't warn me about it
#![allow(clippy::multiple_crate_versions)]
mod calc; mod calc;
mod event; mod event;
mod format; mod format;
use calc::{ use calc::{
constants::{CalculatorAlignment, CalculatorDisplayMode, CalculatorState, RegisterState},
errors::CalculatorResult, errors::CalculatorResult,
types::{CalculatorAlignment, CalculatorDisplayMode, CalculatorState, RegisterState},
Calculator, Calculator,
}; };
use crossterm::{ use crossterm::{
@ -53,7 +59,7 @@ impl Default for App {
Ok(c) => (c, None), Ok(c) => (c, None),
Err(e) => (Calculator::default(), Some(format!("{}", e))), Err(e) => (Calculator::default(), Some(format!("{}", e))),
}; };
App { Self {
calculator, calculator,
error_msg, error_msg,
state: AppState::Calculator, state: AppState::Calculator,
@ -61,11 +67,13 @@ impl Default for App {
} }
} }
impl App { impl App {
fn draw_clippy_dialogs<T: std::io::Write>(&mut self, f: &mut Frame<CrosstermBackend<T>>) { // This function is long because it contains help text
#[allow(clippy::too_many_lines)]
fn draw_clippy_dialogs<T: Write>(&mut self, f: &mut Frame<CrosstermBackend<T>>) {
match (&self.state, &self.calculator.state) { match (&self.state, &self.calculator.state) {
(AppState::Help, _) => { (AppState::Help, _) => {
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { &ClippyRectangle {
title: "Help", title: "Help",
msg: "\ msg: "\
+ => Add s => Sin\n\ + => Add s => Sin\n\
@ -92,7 +100,7 @@ impl App {
} }
(AppState::Calculator, CalculatorState::WaitingForConstant) => { (AppState::Calculator, CalculatorState::WaitingForConstant) => {
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { &ClippyRectangle {
title: "Constants", title: "Constants",
msg: self msg: self
.calculator .calculator
@ -113,7 +121,7 @@ impl App {
RegisterState::Load => "Registers", RegisterState::Load => "Registers",
}; };
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { &ClippyRectangle {
title, title,
msg: self msg: self
.calculator .calculator
@ -128,7 +136,7 @@ impl App {
} }
(AppState::Calculator, CalculatorState::WaitingForMacro) => { (AppState::Calculator, CalculatorState::WaitingForMacro) => {
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { &ClippyRectangle {
title: "Macros", title: "Macros",
msg: self msg: self
.calculator .calculator
@ -143,7 +151,7 @@ impl App {
} }
(AppState::Calculator, CalculatorState::WaitingForSetting) => { (AppState::Calculator, CalculatorState::WaitingForSetting) => {
draw_clippy_rect( draw_clippy_rect(
ClippyRectangle { &ClippyRectangle {
title: "Settings", title: "Settings",
msg: "\ msg: "\
d => Degrees\n\ d => Degrees\n\
@ -170,7 +178,7 @@ impl App {
} }
} }
pub fn terminal_draw_func<T: std::io::Write>(&mut self, f: &mut Frame<CrosstermBackend<T>>) { pub fn terminal_draw_func<T: Write>(&mut self, f: &mut Frame<CrosstermBackend<T>>) {
let chunks = Layout::default() let chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
.margin(2) .margin(2)
@ -304,7 +312,7 @@ fn main() -> Result<(), Box<dyn Error>> {
Err(e) => Some(format!("{}", e)), Err(e) => Some(format!("{}", e)),
}; };
} }
_ => continue, Event::Tick => continue,
} }
} }
} }
@ -318,6 +326,8 @@ fn main() -> Result<(), Box<dyn Error>> {
app.calculator.close().map_err(|e| e.into()) app.calculator.close().map_err(|e| e.into())
} }
// This function is long since it maps keys to their proper value
#[allow(clippy::too_many_lines)]
fn handle_key(app: &mut App, key: KeyEvent) -> CalculatorResult<CalculatorResponse> { fn handle_key(app: &mut App, key: KeyEvent) -> CalculatorResult<CalculatorResponse> {
match (&app.state, &app.calculator.state) { match (&app.state, &app.calculator.state) {
(AppState::Calculator, CalculatorState::Normal) => match key { (AppState::Calculator, CalculatorState::Normal) => match key {
@ -452,7 +462,7 @@ impl ClippyRectangle<'_> {
} }
} }
fn draw_clippy_rect<T: std::io::Write>(c: ClippyRectangle, f: &mut Frame<CrosstermBackend<T>>) { fn draw_clippy_rect<T: Write>(c: &ClippyRectangle, f: &mut Frame<CrosstermBackend<T>>) {
// let block = Block::default().title(c.title).borders(Borders::ALL); // let block = Block::default().title(c.title).borders(Borders::ALL);
let dimensions = c.size(); let dimensions = c.size();
let popup_layout = Layout::default() let popup_layout = Layout::default()