sci_cream/properties.rs
1//! Types that encapsulate various properties of ice cream mixes
2
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "wasm")]
6use wasm_bindgen::prelude::*;
7
8use crate::{
9 composition::{CompKey, Composition},
10 fpd::{FPD, FpdKey},
11};
12
13/// Keys for accessing specific property values from [`MixProperties`] via [`MixProperties::get()`]
14///
15/// This enum wraps both [`CompKey`] and [`FpdKey`] to allow accessing all properties from a single
16/// interface, which is helpful in downstream applications, to have a single flattened list of keys.
17/// There are [`From`] implementations for both key types to facilitate easy conversion.
18///
19/// # Example
20///
21/// ```
22/// use sci_cream::{CompKey, FpdKey, PropKey, MixProperties};
23/// let mix_props = MixProperties::empty();
24/// assert_eq!(mix_props.get(CompKey::MilkFat.into()), 0.0);
25/// assert_eq!(mix_props.get(FpdKey::FPD.into()), 0.0);
26/// ```
27#[derive(Hash, PartialEq, Eq, Serialize, Deserialize, Copy, Clone, Debug)]
28pub enum PropKey {
29 /// [`CompKey`] for [`Composition`] properties from [`MixProperties::composition`]
30 CompKey(CompKey),
31 /// [`FpdKey`] for [`FPD`] properties from [`MixProperties::fpd`]
32 FpdKey(FpdKey),
33}
34
35impl From<CompKey> for PropKey {
36 fn from(key: CompKey) -> Self {
37 Self::CompKey(key)
38 }
39}
40
41impl From<FpdKey> for PropKey {
42 fn from(key: FpdKey) -> Self {
43 Self::FpdKey(key)
44 }
45}
46
47/// Properties of an ice cream mix, including [`Composition`] and freezing point depression [`FPD`]
48#[cfg_attr(feature = "wasm", wasm_bindgen)]
49#[derive(Clone, Debug)]
50pub struct MixProperties {
51 /// Total amount of the mix in grams
52 pub total_amount: f64,
53 /// Composition properties of the mix
54 pub composition: Composition,
55 /// [Freezing Point Depression (FPD)](crate::docs#freezing-point-depression)
56 #[cfg_attr(feature = "wasm", wasm_bindgen(getter_with_clone))]
57 pub fpd: FPD,
58}
59
60impl MixProperties {
61 /// Creates an empty [`MixProperties`], with properties equivalent to those of 100% water.
62 #[must_use]
63 pub fn empty() -> Self {
64 Self {
65 total_amount: 0.0,
66 composition: Composition::empty(),
67 fpd: FPD::empty(),
68 }
69 }
70
71 /// Access specific mix property values via an [`PropKey`]
72 #[must_use]
73 pub fn get(&self, key: PropKey) -> f64 {
74 match key {
75 PropKey::CompKey(comp_key) => self.composition.get(comp_key),
76 PropKey::FpdKey(fpd_key) => self.fpd.get(fpd_key),
77 }
78 }
79}
80
81#[cfg_attr(feature = "wasm", wasm_bindgen)]
82impl MixProperties {
83 /// Creates a new empty [`MixProperties`], forwards to [`MixProperties::empty`].
84 #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
85 #[must_use]
86 pub fn new() -> Self {
87 Self::empty()
88 }
89}
90
91impl Default for MixProperties {
92 fn default() -> Self {
93 Self::empty()
94 }
95}