Skip to main content

QuantityFunction

Struct QuantityFunction 

Source
pub struct QuantityFunction<T>
where T: IsQuantity,
{ /* private fields */ }
Expand description

A thin wrapper around a Box<dyn IsQuantityFunction> trait object which provides some type checks for usage in VarQuantity.

This struct wraps a Box<dyn IsQuantityFunction> so it can be used in the VarQuantity::Function enum variant. As explained in the IsQuantityFunction docstring, the unit of the DynQuantity returned by IsQuantityFunction::call must always be the same. Even though this can unfortunately not be represented by the type system for reasons outlined in the trait docstring, this wrapper provides some checks to reduce the likelihood of wrong units:

This struct has the same memory representation as Box<dyn IsQuantityFunction>. The underlying trait object can be retrieved directly via QuantityFunction::into_inner or accessed via AsRef::as_ref and Deref::deref.

§Features

This struct can be serialized / deserialized if the serde feature is enabled. Since it is just a wrapper around a Box<dyn IsQuantityFunction> trait object, it serializes directly to the representation of that object and deserializes directly from it (it is“transparent”).

Implementations§

Source§

impl<T> QuantityFunction<T>
where T: IsQuantity,

Source

pub fn new( function: Box<dyn IsQuantityFunction>, ) -> Result<QuantityFunction<T>, UnitsNotEqual>

Creates a new instance of Self and performs a type safety check by running the IsQuantityFunction::call of function with an empty slice as conditions. The unit of the resulting DynQuantity is then compared to that created by T::unit_from_type. If they don’t match, an error is returned. See the docstring of QuantityFunction for more.

§Examples
use var_quantity::{DynQuantity, PredefUnit, Unit};
use var_quantity::{IsQuantityFunction, QuantityFunction};
use var_quantity::uom::si::f64::{ElectricalResistance, ElectricCurrent};

// The serde annotations are just here because the doctests of this crate use
// the serde feature - they are not needed if the serde feature is disabled.
#[derive(Clone, serde::Deserialize, serde::Serialize, PartialEq)]
struct Resistance;

// Again, the macro annotation is just here because of the serde feature
#[typetag::serde]
impl IsQuantityFunction for Resistance {
    fn call(&self, conditions: &[DynQuantity<f64>]) -> DynQuantity<f64> {
        return DynQuantity::new(1.0, PredefUnit::ElectricResistance);
    }

    fn dyn_eq(&self, other: &dyn IsQuantityFunction) -> bool {
        (other as &dyn std::any::Any).downcast_ref::<Self>() == Some(self)
    }
}

let resistance = Resistance {};

// The Resistance struct always returns an electric resistance. Hence the
// type check fails for other types
assert!(QuantityFunction::<ElectricalResistance>::new(Box::new(resistance.clone())).is_ok());
assert!(QuantityFunction::<f64>::new(Box::new(resistance.clone())).is_err());
assert!(QuantityFunction::<ElectricCurrent>::new(Box::new(resistance.clone())).is_err());
Source

pub fn call(&self, conditions: &[DynQuantity<f64>]) -> T

Forwards the input to the IsQuantityFunction::call method of the wrapped trait object and asserts that the returned value can be converted to T. If that is not the case, the constraint outlined in the docstring of QuantityFunction is not fulfilled and the code is invalid, therefore the function panics.

§Examples

This is a valid implementation of IsQuantity: Unit is always the same regardless of input.

use var_quantity::{DynQuantity, PredefUnit, Unit, IsQuantityFunction, QuantityFunction};
use var_quantity::uom::si::electrical_resistance::ohm;
use var_quantity::uom::si::f64::{ElectricalResistance};

// The serde annotations are just here because the doctests of this crate use
// the serde feature - they are not needed if the serde feature is disabled.
#[derive(Clone, serde::Deserialize, serde::Serialize, PartialEq)]
struct Resistance;

// Again, the macro annotation is just here because of the serde feature
#[typetag::serde]
impl IsQuantityFunction for Resistance {
    fn call(&self, conditions: &[DynQuantity<f64>]) -> DynQuantity<f64> {
        return DynQuantity::new(1.0, PredefUnit::ElectricResistance);
    }

    fn dyn_eq(&self, other: &dyn IsQuantityFunction) -> bool {
        (other as &dyn std::any::Any).downcast_ref::<Self>() == Some(self)
    }
}

let wrapped_resistance = QuantityFunction::<ElectricalResistance>::new(Box::new(Resistance {})).expect("units match");
assert_eq!(ElectricalResistance::new::<ohm>(1.0), wrapped_resistance.call(&[1.0.into()]));

This is an invalid (and nonsensical) implementation of IsQuantityFunction where the output unit changes with the number of arguments:

use var_quantity::{DynQuantity, PredefUnit, Unit};
use var_quantity::{IsQuantityFunction, QuantityFunction};
use var_quantity::uom::si::f64::{ElectricalResistance};

// The serde annotations are just here because the doctests of this crate use
// the serde feature - they are not needed if the serde feature is disabled.
#[derive(Clone, serde::Deserialize, serde::Serialize, PartialEq)]
struct Resistance;

// Again, the macro annotation is just here because of the serde feature
#[typetag::serde]
impl IsQuantityFunction for Resistance {
    fn call(&self, conditions: &[DynQuantity<f64>]) -> DynQuantity<f64> {
        if conditions.len() == 0 {
            return DynQuantity::new(1.0, PredefUnit::ElectricResistance);
        } else {
            return DynQuantity::new(1.0, PredefUnit::None);
        }
    }

    fn dyn_eq(&self, other: &dyn IsQuantityFunction) -> bool {
        (other as &dyn std::any::Any).downcast_ref::<Self>() == Some(self)
    }
}

// Construction succeeds since the test call is done with an empty slice
let wrapped_resistance = QuantityFunction::<ElectricalResistance>::new(Box::new(Resistance {})).expect("units match");

// ... but calling with a quantity results in a panic
let _ = wrapped_resistance.call(&[DynQuantity::new(1.0, PredefUnit::None)]);
Source

pub fn into_inner(self) -> Box<dyn IsQuantityFunction>

Returns the underlying boxed IsQuantityFunction trait object.

Trait Implementations§

Source§

impl<T> AsRef<dyn IsQuantityFunction> for QuantityFunction<T>
where T: IsQuantity,

Source§

fn as_ref(&self) -> &(dyn IsQuantityFunction + 'static)

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl<T> Clone for QuantityFunction<T>
where T: IsQuantity,

Source§

fn clone(&self) -> QuantityFunction<T>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Debug for QuantityFunction<T>
where T: IsQuantity,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<'de, T> Deserialize<'de> for QuantityFunction<T>
where T: IsQuantity,

Source§

fn deserialize<D>( deserializer: D, ) -> Result<QuantityFunction<T>, <D as Deserializer<'de>>::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> PartialEq for QuantityFunction<T>
where T: IsQuantity,

Source§

fn eq(&self, other: &QuantityFunction<T>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T> Serialize for QuantityFunction<T>
where T: IsQuantity,

Source§

fn serialize<S>( &self, serializer: S, ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<T> Deref for QuantityFunction<T>
where T: IsQuantity,

Source§

type Target = dyn IsQuantityFunction

The resulting type after dereferencing.
Source§

fn deref(&self) -> &(dyn IsQuantityFunction + 'static)

Dereferences the value.

Auto Trait Implementations§

§

impl<T> Freeze for QuantityFunction<T>

§

impl<T> !RefUnwindSafe for QuantityFunction<T>

§

impl<T> Send for QuantityFunction<T>
where T: Send,

§

impl<T> Sync for QuantityFunction<T>
where T: Sync,

§

impl<T> Unpin for QuantityFunction<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for QuantityFunction<T>

§

impl<T> !UnwindSafe for QuantityFunction<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> SendAlias for T

Source§

impl<T> SyncAlias for T