use approx::AbsDiffEq;
use serde::{Deserialize, Serialize};
use crate::{
composition::{ArtificialSweeteners, Polyols, ScaleComponents, Sugars},
error::Result,
};
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;
#[cfg(doc)]
use crate::{composition::Composition, error::Error, specs::SweetenerSpec};
#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[derive(PartialEq, Serialize, Deserialize, Copy, Clone, Debug)]
#[serde(default, deny_unknown_fields)]
pub struct Sweeteners {
pub sugars: Sugars,
pub polyols: Polyols,
pub artificial: ArtificialSweeteners,
}
impl Sweeteners {
#[must_use]
pub const fn empty() -> Self {
Self {
sugars: Sugars::empty(),
polyols: Polyols::empty(),
artificial: ArtificialSweeteners::empty(),
}
}
#[must_use]
pub const fn new() -> Self {
Self::empty()
}
#[must_use]
pub const fn sugars(self, sugars: Sugars) -> Self {
Self { sugars, ..self }
}
#[must_use]
pub const fn polyols(self, polyols: Polyols) -> Self {
Self { polyols, ..self }
}
#[must_use]
pub const fn artificial(self, artificial: ArtificialSweeteners) -> Self {
Self { artificial, ..self }
}
#[must_use]
pub fn total(&self) -> f64 {
self.sugars.total() + self.polyols.total() + self.artificial.total()
}
pub fn to_pod(&self) -> Result<f64> {
Ok(self.sugars.to_pod()? + self.polyols.to_pod()? + self.artificial.to_pod()?)
}
pub fn to_pac(&self) -> Result<f64> {
Ok(self.sugars.to_pac()? + self.polyols.to_pac()? + self.artificial.to_pac()?)
}
}
#[cfg_attr(coverage, coverage(off))]
#[cfg(feature = "wasm")]
#[wasm_bindgen]
impl Sweeteners {
#[allow(clippy::missing_const_for_fn)] #[wasm_bindgen(constructor)]
#[must_use]
pub fn new_wasm() -> Self {
Self::new()
}
}
impl ScaleComponents for Sweeteners {
fn scale(&self, factor: f64) -> Self {
Self {
sugars: self.sugars.scale(factor),
polyols: self.polyols.scale(factor),
artificial: self.artificial.scale(factor),
}
}
fn add(&self, other: &Self) -> Self {
Self {
sugars: self.sugars.add(&other.sugars),
polyols: self.polyols.add(&other.polyols),
artificial: self.artificial.add(&other.artificial),
}
}
}
impl AbsDiffEq for Sweeteners {
type Epsilon = f64;
fn default_epsilon() -> Self::Epsilon {
f64::default_epsilon()
}
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
self.sugars.abs_diff_eq(&other.sugars, epsilon)
&& self.polyols.abs_diff_eq(&other.polyols, epsilon)
&& self.artificial.abs_diff_eq(&other.artificial, epsilon)
}
}
impl Default for Sweeteners {
fn default() -> Self {
Self::empty()
}
}