#[cfg(feature = "astrophysics")]
pub mod brightness_temperature;
pub mod dimensionless_angles;
#[cfg(feature = "astrophysics")]
pub mod doppler;
#[cfg(feature = "logarithmic")]
pub mod logarithmic;
pub mod mass_energy;
#[cfg(feature = "astrophysics")]
pub mod parallax;
#[cfg(feature = "astrophysics")]
pub mod spectral;
#[cfg(feature = "astrophysics")]
pub mod spectral_density;
pub mod temperature;
use crate::error::{UnitError, UnitResult};
use crate::quantity::Quantity;
use crate::unit::Unit;
use std::sync::Arc;
pub type ConverterFn = Arc<dyn Fn(&Unit, &Unit) -> Option<Converter> + Send + Sync>;
#[derive(Clone)]
pub struct Equivalency {
name: &'static str,
converter_fn: ConverterFn,
}
impl Equivalency {
pub fn new<F>(name: &'static str, converter_fn: F) -> Self
where
F: Fn(&Unit, &Unit) -> Option<Converter> + Send + Sync + 'static,
{
Equivalency {
name,
converter_fn: Arc::new(converter_fn),
}
}
pub fn name(&self) -> &str {
self.name
}
pub fn get_converter(&self, from: &Unit, to: &Unit) -> Option<Converter> {
(self.converter_fn)(from, to)
}
}
impl std::fmt::Debug for Equivalency {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Equivalency({})", self.name())
}
}
pub struct Converter {
forward: Box<dyn Fn(f64) -> Result<f64, String> + Send + Sync>,
backward: Box<dyn Fn(f64) -> Result<f64, String> + Send + Sync>,
}
impl Converter {
pub fn new<F, B>(forward: F, backward: B) -> Self
where
F: Fn(f64) -> Result<f64, String> + Send + Sync + 'static,
B: Fn(f64) -> Result<f64, String> + Send + Sync + 'static,
{
Converter {
forward: Box::new(forward),
backward: Box::new(backward),
}
}
pub fn new_infallible<F, B>(forward: F, backward: B) -> Self
where
F: Fn(f64) -> f64 + Send + Sync + 'static,
B: Fn(f64) -> f64 + Send + Sync + 'static,
{
Converter {
forward: Box::new(move |x| Ok(forward(x))),
backward: Box::new(move |x| Ok(backward(x))),
}
}
pub fn convert(&self, value: f64) -> Result<f64, String> {
(self.forward)(value)
}
pub fn convert_back(&self, value: f64) -> Result<f64, String> {
(self.backward)(value)
}
}
impl Quantity {
pub fn to_equiv(&self, target: impl Into<Unit>, equiv: Equivalency) -> UnitResult<Quantity> {
self.to_equiv_list(target, &[equiv])
}
pub fn to_equiv_list(
&self,
target: impl Into<Unit>,
equivs: &[Equivalency],
) -> UnitResult<Quantity> {
let target = target.into();
if self.unit().dimension() == target.dimension() {
let si_value = self.unit().to_si(self.value());
return Ok(Quantity::new(target.from_si(si_value), target));
}
for equiv in equivs {
if let Some(converter) = equiv.get_converter(self.unit(), &target) {
let si_value = self.unit().to_si(self.value());
let converted_si =
converter
.convert(si_value)
.map_err(|msg| UnitError::NoEquivalency {
from: format!("{} ({})", self.unit(), msg),
to: target.to_string(),
})?;
let target_value = target.from_si(converted_si);
return Ok(Quantity::new(target_value, target));
}
}
Err(UnitError::NoEquivalency {
from: self.unit().to_string(),
to: target.to_string(),
})
}
}
#[cfg(feature = "astrophysics")]
pub use brightness_temperature::{
brightness_temperature, brightness_temperature_intensity, brightness_temperature_planck,
};
pub use dimensionless_angles::dimensionless_angles;
#[cfg(feature = "astrophysics")]
pub use doppler::{doppler_optical, doppler_radio, doppler_relativistic};
#[cfg(feature = "logarithmic")]
pub use logarithmic::{db_amplitude, db_power, dex_ratio, magnitude_flux};
pub use mass_energy::mass_energy;
#[cfg(feature = "astrophysics")]
pub use parallax::parallax;
#[cfg(feature = "astrophysics")]
pub use spectral::spectral;
#[cfg(feature = "astrophysics")]
pub use spectral_density::{ab_magnitude, ab_magnitude_lambda, spectral_density};
pub use temperature::{temperature, temperature_energy};