//! Traits for working generically with dimensioned
//!
//! Unless specified otherwise, all of these traits are implemented for the unit systems that come
//! with dimensioned and with any created by the `make_units!` macro.
/// Allows one to refer to quantities generically.
///
/// It is not recommened to implement this for anything outside this this crate.
/// This trait is implemented for all quantities with no units. The unit systems that come with
/// dimensioned use `Unitless<V>` for that type.
/// Perform an operation on a quantity.
///
/// Use of this function is discouraged except when necessary, as the operation may be one that
/// does not perserve units, and this function has no way to protect against that. If you do use
/// it, consider placing it in a trait or function that you can verify is dimensionally safe.
///
/// If associated type constructors or higher kinded types are implemented, then this trait should
/// no longer be necessary and may become deprecated.
///
/// # Example
///
/// Let's say we have a function that, when given a quantity with value type `Value` and unit type
/// `Units`, has output with value type `(Value, Value)` and squares the units. Then, we could
/// generically implement it for `Dimensioned` as follows:
///
/// ```rust
/// extern crate dimensioned as dim;
///
/// use dim::{Dimensioned, MapUnsafe};
/// use dim::typenum::{Prod, P2};
/// use std::ops::Mul;
///
/// pub trait Weird {
/// type Output;
/// fn weird(self) -> Self::Output;
/// }
///
/// impl<D, Value, Units> Weird for D where
/// Value: Clone,
/// Units: Mul<P2>,
/// D: Dimensioned<Value=Value, Units=Units> +
/// MapUnsafe<(Value, Value), Prod<Units, P2>>,
/// {
/// type Output = <D as MapUnsafe<(Value, Value), Prod<Units, P2>>>::Output;
/// fn weird(self) -> Self::Output {
/// self.map_unsafe(|v| (v.clone(), v))
/// }
/// }
///
/// fn main() {
/// use dim::si;
/// let x = 3.0 * si::M;
/// let w = x.weird();
///
/// assert_eq!(w, si::Meter2::new((3.0, 3.0)));
///
/// println!("w: {:?}", w);
/// // prints: w: (3, 3) m^2
/// }
/// ```
/// Perform an operation on the contained value.
///
/// This trait is only defined for unitless types, and it keeps them unitless, so it is
/// perfectly safe to use.
///
/// It can be used similarly to `MapUnsafe`, but only for `Dimensionless` quantities, and it cannot
/// make them non-`Dimensionless`.
///
/// # Example
///
/// ```rust
/// extern crate dimensioned as dim;
///
/// fn main() {
/// use dim::si;
/// let x1 = 2.0 * si::ONE;
/// let x2 = 2.0f64;
///
/// use dim::Map;
/// assert_eq!(x1.map(|v| v.sin()), x2.sin() * si::ONE);
/// }
/// ```
/// Everything that is not a quantity implements this trait
/// `Recip` is used for implementing a `recip()` member for types that are not preserved under
/// reciprocal.
///
/// # Example
/// ```rust
/// extern crate dimensioned as dim;
/// use dim::si;
///
/// fn main() {
/// let t = 2.0 * si::S;
/// let f = 0.5 * si::HZ;
///
/// use dim::Recip;
/// assert_eq!(t.recip(), f);
/// }
/// ```
impl_unary!;
impl_unary!;
/// `Root` is used for implementing general integer roots for types that aren't necessarily
/// preserved under root.
///
/// It uses instantiated type numbers to specify the degree, as you can see in the example below.
///
/// # Example
/// ```rust
/// extern crate dimensioned as dim;
///
/// fn main() {
/// use dim::Root;
/// use dim::typenum::P2;
/// let x = 4.0.root(P2::new());
/// let y = 2.0;
///
/// assert_eq!(x, y);
/// }
/// ```
use Integer;
impl_root!;
impl_root!;
/// `Sqrt` provides a `sqrt` member function for types that are not necessarily preserved under
/// square root.
///
/// # Example
///
/// ```rust
/// extern crate dimensioned as dim;
///
/// fn main() {
/// use dim::si;
/// let x = 2.0 * si::M;
/// let a = 4.0 * si::M2;
///
/// use dim::Sqrt;
/// assert_eq!(a.sqrt(), x);
/// }
/// ```
/// `Cbrt` provides a `cbrt` member function for types that are not necessarily preserved under
/// cube root.
///
/// # Example
///
/// ```rust
/// extern crate dimensioned as dim;
///
/// fn main() {
/// use dim::si;
/// let x = 2.0 * si::M;
/// let v = 8.0 * si::M3;
///
/// use dim::Cbrt;
/// assert_eq!(v.cbrt(), x);
/// }
/// ```
impl_sqcbroot!;
impl_sqcbroot!;