use crate::units::length::{Centimeter, Kilometer, Meter, Millimeter};
use crate::{Prod, Quantity, Unit};
pub use crate::dimension::Area;
pub trait AreaUnit: Unit<Dim = Area> {}
impl<T: Unit<Dim = Area>> AreaUnit for T {}
pub type SquareOf<L> = Quantity<Prod<L, L>>;
#[cfg(feature = "land-area")]
mod land_area;
#[cfg(feature = "land-area")]
pub use land_area::*;
#[cfg(feature = "customary")]
mod customary;
#[cfg(feature = "customary")]
pub use customary::*;
pub type SquareMeter = Prod<Meter, Meter>;
pub type SquareMeters = Quantity<SquareMeter>;
pub type SquareKilometer = Prod<Kilometer, Kilometer>;
pub type SquareKilometers = Quantity<SquareKilometer>;
pub type SquareCentimeter = Prod<Centimeter, Centimeter>;
pub type SquareCentimeters = Quantity<SquareCentimeter>;
pub type SquareMillimeter = Prod<Millimeter, Millimeter>;
pub type SquareMillimeters = Quantity<SquareMillimeter>;
#[macro_export]
#[doc(hidden)]
macro_rules! area_units {
($cb:path) => {
$cb!(
SquareMeter,
SquareKilometer,
SquareCentimeter,
SquareMillimeter
);
};
}
area_units!(crate::impl_unit_from_conversions);
#[cfg(feature = "cross-unit-ops")]
area_units!(crate::impl_unit_cross_unit_ops);
#[cfg(all(feature = "customary", feature = "land-area"))]
crate::__impl_from_each_extra_to_bases!(
{SquareInch, SquareFoot, SquareYard, SquareMile}
Hectare, Are, Acre
);
#[cfg(all(
feature = "customary",
feature = "land-area",
feature = "cross-unit-ops"
))]
crate::__impl_cross_ops_each_extra_to_bases!(
{SquareInch, SquareFoot, SquareYard, SquareMile}
Hectare, Are, Acre
);
#[cfg(test)]
area_units!(crate::assert_units_are_builtin);
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
#[test]
fn sqm_to_sqkm() {
let a = SquareMeters::new(1_000_000.0);
let b: SquareKilometers = a.to();
assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
}
#[test]
#[cfg(feature = "land-area")]
fn hectare_to_sqm() {
let a = Hectares::new(1.0);
let b: SquareMeters = a.to();
assert_abs_diff_eq!(b.value(), 10_000.0, epsilon = 1e-9);
}
#[test]
#[cfg(feature = "land-area")]
fn acre_to_hectare() {
let a = Acres::new(1.0);
let b: Hectares = a.to();
assert_abs_diff_eq!(b.value(), 0.404_685_642_24, epsilon = 1e-9);
}
#[test]
#[cfg(feature = "customary")]
fn sqft_to_sqm() {
let a = SquareFeet::new(1.0);
let b: SquareMeters = a.to();
assert_abs_diff_eq!(b.value(), 0.092_903_04, epsilon = 1e-9);
}
#[test]
fn length_product_is_area() {
use crate::length::Meters;
let side = Meters::new(5.0);
let area: SquareMeters = side * side; assert_abs_diff_eq!(area.value(), 25.0, epsilon = 1e-12);
}
#[test]
#[cfg(feature = "customary")]
fn sqmile_to_sqkm() {
let a = SquareMiles::new(1.0);
let b: SquareKilometers = a.to();
assert_abs_diff_eq!(b.value(), 2.589_988_110_336, epsilon = 1e-6);
}
#[test]
fn sqcm_to_sqm() {
let a = SquareCentimeters::new(10_000.0);
let b: SquareMeters = a.to();
assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
}
#[test]
fn sqmm_to_sqcm() {
let a = SquareMillimeters::new(100.0);
let b: SquareCentimeters = a.to();
assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
}
#[test]
#[cfg(feature = "land-area")]
fn are_to_sqm() {
let a = Ares::new(1.0);
let b: SquareMeters = a.to();
assert_abs_diff_eq!(b.value(), 100.0, epsilon = 1e-12);
}
#[test]
#[cfg(feature = "customary")]
fn sqinch_to_sqcm() {
let a = SquareInches::new(1.0);
let b: SquareCentimeters = a.to();
assert_abs_diff_eq!(b.value(), 6.4516, epsilon = 1e-9);
}
#[test]
#[cfg(feature = "customary")]
fn sqyard_to_sqm() {
let a = SquareYards::new(1.0);
let b: SquareMeters = a.to();
assert_abs_diff_eq!(b.value(), 0.836_127_36, epsilon = 1e-9);
}
#[test]
fn roundtrip_sqcm_sqm() {
let original = SquareCentimeters::new(250.0);
let converted = original.to::<SquareMeter>();
let back = converted.to::<SquareCentimeter>();
assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-10);
}
#[test]
fn sqrt_recovers_length_unit() {
use crate::length::{Meter, Meters};
let area = SquareMeters::new(36.0);
let side: crate::Quantity<Meter> = area.sqrt();
assert_abs_diff_eq!(side.value(), 6.0, epsilon = 1e-12);
let again: SquareMeters = side * side;
assert_abs_diff_eq!(again.value(), area.value(), epsilon = 1e-12);
let s = Meters::new(7.0);
let a = s * s;
let r: Meters = a.sqrt();
assert_abs_diff_eq!(r.value(), 7.0, epsilon = 1e-12);
}
#[test]
fn squared_unit_conversion_uses_squared_scale() {
let one_sqkm = SquareKilometers::new(1.0);
let in_sqm: SquareMeters = one_sqkm.to();
assert_abs_diff_eq!(in_sqm.value(), 1.0e6, epsilon = 1e-6);
}
#[test]
#[cfg(feature = "std")]
fn squared_unit_formatter_output() {
assert_eq!(format!("{}", SquareMeters::new(2.5)), "2.5 m·m");
assert_eq!(format!("{:e}", SquareMeters::new(1234.0)), "1.234e3 m·m");
}
#[test]
#[cfg(feature = "std")]
fn symbols_are_correct() {
assert_eq!(format!("{}", SquareMeters::new(1.0)), "1 m·m");
#[cfg(feature = "land-area")]
assert_eq!(Hectare::SYMBOL, "ha");
#[cfg(feature = "land-area")]
assert_eq!(Acre::SYMBOL, "ac");
#[cfg(feature = "customary")]
assert_eq!(SquareInch::SYMBOL, "in²");
}
}