aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.rs47
-rw-r--r--src/volume.rs91
2 files changed, 61 insertions, 77 deletions
diff --git a/src/main.rs b/src/main.rs
index 2c1fa85..4c6cf43 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,45 +1,38 @@
use iced::{
- widget::{column, row, text, text_input},
+ widget::{column, pick_list, row, text, text_input},
Element, Sandbox, Settings,
};
-use volute::volume::{CubicMetre, Volume};
+use volute::volume::{self, CubicMetre};
pub fn main() -> iced::Result {
App::run(Settings::default())
}
+#[derive(Default)]
struct App {
- displacement: Box<dyn Volume>,
+ displacement: CubicMetre,
ui: UI,
}
#[derive(Default)]
struct UI {
displacement: String,
+ displacement_unit: volume::Unit,
}
impl App {
fn set_displacement(&mut self, displacement: &str) {
if displacement.len() == 0 {
- self.displacement.set(0.0);
+ self.displacement.0 = 0.0;
self.ui.displacement = "".to_string();
- } else if let Ok(d) = displacement.parse::<f64>() {
- self.displacement.set(d);
+ } else if let Ok(val) = displacement.parse::<f64>() {
+ self.displacement = CubicMetre::from_unit(self.ui.displacement_unit, val);
self.ui.displacement = String::from(displacement);
}
}
}
-impl Default for App {
- fn default() -> Self {
- Self {
- displacement: Box::new(CubicMetre::default()),
- ui: UI::default(),
- }
- }
-}
-
impl Sandbox for App {
type Message = Message;
@@ -53,17 +46,32 @@ impl Sandbox for App {
fn update(&mut self, message: Message) {
match message {
- Message::DisplacementChanged(displacement) => {
+ Message::Displacement(displacement) => {
self.set_displacement(&displacement);
}
+ Message::DisplacementUnit(unit) => {
+ self.ui.displacement = format!(
+ "{:.2}",
+ volume::convert(
+ self.ui.displacement.parse::<f64>().unwrap(),
+ self.ui.displacement_unit,
+ unit,
+ )
+ );
+ self.ui.displacement_unit = unit;
+ }
}
}
fn view(&self) -> Element<Self::Message> {
column![row![
text("Displacement:"),
- text_input("2.0", &self.ui.displacement, Message::DisplacementChanged),
- text(self.displacement.unit()),
+ text_input("2.0", &self.ui.displacement, Message::Displacement),
+ pick_list(
+ &volume::Unit::ALL[..],
+ Some(self.ui.displacement_unit),
+ Message::DisplacementUnit,
+ ),
]]
.into()
}
@@ -71,5 +79,6 @@ impl Sandbox for App {
#[derive(Debug, Clone)]
pub enum Message {
- DisplacementChanged(String),
+ Displacement(String),
+ DisplacementUnit(volume::Unit),
}
diff --git a/src/volume.rs b/src/volume.rs
index 675dfaa..933ae49 100644
--- a/src/volume.rs
+++ b/src/volume.rs
@@ -3,22 +3,17 @@ use std::{
ops::Mul,
};
-pub trait Volume {
- /// Returns the volume in SI units (cubic metres).
- fn si(self) -> CubicMetre;
-
- fn set(&mut self, val: f64);
-
- fn unit(&self) -> Unit;
-
- fn convert(self, unit: Unit) -> Box<dyn Volume>;
-}
-
+#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub enum Unit {
+ #[default]
CubicMetre,
Litre,
}
+impl Unit {
+ pub const ALL: [Self; 2] = [Self::CubicMetre, Self::Litre];
+}
+
impl Display for Unit {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
@@ -33,62 +28,29 @@ impl Display for Unit {
}
#[derive(Debug, Default, PartialEq)]
-pub struct CubicMetre(f64);
+pub struct CubicMetre(pub f64);
-impl Volume for CubicMetre {
- fn si(self) -> CubicMetre {
- self
- }
-
- fn set(&mut self, val: f64) {
- self.0 = val;
- }
-
- fn unit(&self) -> Unit {
- Unit::CubicMetre
- }
-
- fn convert(self, unit: Unit) -> Box<dyn Volume> {
+impl CubicMetre {
+ pub fn from_unit<F: Into<f64>>(unit: Unit, value: F) -> Self {
match unit {
- Unit::CubicMetre => Box::new(self),
- Unit::Litre => Box::new(Litre::from(self)),
+ Unit::CubicMetre => Self(value.into()),
+ Unit::Litre => Self::from(Litre(value.into())),
}
}
}
impl From<Litre> for CubicMetre {
fn from(value: Litre) -> Self {
- value.si()
+ Self(value.0 * 10_f64.powf(-3.))
}
}
#[derive(Debug, PartialEq)]
struct Litre(f64);
-impl Volume for Litre {
- fn si(self) -> CubicMetre {
- CubicMetre(self.0 * 10_f64.powf(-3.))
- }
-
- fn set(&mut self, val: f64) {
- self.0 = val
- }
-
- fn unit(&self) -> Unit {
- Unit::Litre
- }
-
- fn convert(self, unit: Unit) -> Box<dyn Volume> {
- match unit {
- Unit::CubicMetre => Box::new(CubicMetre::from(self)),
- Unit::Litre => Box::new(self),
- }
- }
-}
-
-impl From<i32> for Litre {
- fn from(value: i32) -> Self {
- Self(value as f64)
+impl<F: Into<f64>> From<F> for Litre {
+ fn from(value: F) -> Self {
+ Self(value.into())
}
}
@@ -98,21 +60,34 @@ impl From<CubicMetre> for Litre {
}
}
-impl Mul<f64> for Litre {
+impl<F: Into<f64>> Mul<F> for Litre {
type Output = Self;
- fn mul(self, rhs: f64) -> Self::Output {
- Self(self.0 * rhs)
+ fn mul(self, rhs: F) -> Self::Output {
+ Self(self.0 * rhs.into())
+ }
+}
+
+pub fn convert<F: Into<f64>>(val: F, from: Unit, to: Unit) -> f64 {
+ match from {
+ Unit::CubicMetre => match to {
+ Unit::CubicMetre => val.into(),
+ Unit::Litre => Litre::from(CubicMetre(val.into())).0,
+ },
+ Unit::Litre => match to {
+ Unit::Litre => val.into(),
+ Unit::CubicMetre => CubicMetre::from(Litre(val.into())).0,
+ },
}
}
#[cfg(test)]
mod tests {
- use crate::volume::{CubicMetre, Litre, Volume};
+ use super::{CubicMetre, Litre};
#[test]
fn litre_to_cubic_metre() {
- assert_eq!(Litre(1000.).si(), CubicMetre(1.))
+ assert_eq!(CubicMetre::from(Litre(1000.)), CubicMetre(1.))
}
#[test]