qtty_core/units/area/
mod.rs1use crate::units::length::{Centimeter, Kilometer, Meter, Millimeter};
41use crate::{Prod, Quantity, Unit};
42
43pub use crate::dimension::Area;
45
46pub trait AreaUnit: Unit<Dim = Area> {}
48impl<T: Unit<Dim = Area>> AreaUnit for T {}
49
50pub type SquareOf<L> = Quantity<Prod<L, L>>;
71
72#[cfg(feature = "land-area")]
73mod land_area;
74#[cfg(feature = "land-area")]
75pub use land_area::*;
76#[cfg(feature = "customary")]
77mod customary;
78#[cfg(feature = "customary")]
79pub use customary::*;
80
81pub type SquareMeter = Prod<Meter, Meter>;
87pub type SquareMeters = Quantity<SquareMeter>;
89
90pub type SquareKilometer = Prod<Kilometer, Kilometer>;
92pub type SquareKilometers = Quantity<SquareKilometer>;
94
95pub type SquareCentimeter = Prod<Centimeter, Centimeter>;
97pub type SquareCentimeters = Quantity<SquareCentimeter>;
99
100pub type SquareMillimeter = Prod<Millimeter, Millimeter>;
102pub type SquareMillimeters = Quantity<SquareMillimeter>;
104
105#[macro_export]
125#[doc(hidden)]
126macro_rules! area_units {
127 ($cb:path) => {
128 $cb!(
129 SquareMeter,
130 SquareKilometer,
131 SquareCentimeter,
132 SquareMillimeter
133 );
134 };
135}
136
137area_units!(crate::impl_unit_from_conversions);
139
140#[cfg(feature = "cross-unit-ops")]
142area_units!(crate::impl_unit_cross_unit_ops);
143
144#[cfg(all(feature = "customary", feature = "land-area"))]
146crate::__impl_from_each_extra_to_bases!(
147 {SquareInch, SquareFoot, SquareYard, SquareMile}
148 Hectare, Are, Acre
149);
150#[cfg(all(
151 feature = "customary",
152 feature = "land-area",
153 feature = "cross-unit-ops"
154))]
155crate::__impl_cross_ops_each_extra_to_bases!(
156 {SquareInch, SquareFoot, SquareYard, SquareMile}
157 Hectare, Are, Acre
158);
159
160#[cfg(test)]
162area_units!(crate::assert_units_are_builtin);
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use approx::assert_abs_diff_eq;
168
169 #[test]
170 fn sqm_to_sqkm() {
171 let a = SquareMeters::new(1_000_000.0);
172 let b: SquareKilometers = a.to();
173 assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
174 }
175
176 #[test]
177 #[cfg(feature = "land-area")]
178 fn hectare_to_sqm() {
179 let a = Hectares::new(1.0);
180 let b: SquareMeters = a.to();
181 assert_abs_diff_eq!(b.value(), 10_000.0, epsilon = 1e-9);
182 }
183
184 #[test]
185 #[cfg(feature = "land-area")]
186 fn acre_to_hectare() {
187 let a = Acres::new(1.0);
188 let b: Hectares = a.to();
189 assert_abs_diff_eq!(b.value(), 0.404_685_642_24, epsilon = 1e-9);
190 }
191
192 #[test]
193 #[cfg(feature = "customary")]
194 fn sqft_to_sqm() {
195 let a = SquareFeet::new(1.0);
196 let b: SquareMeters = a.to();
197 assert_abs_diff_eq!(b.value(), 0.092_903_04, epsilon = 1e-9);
198 }
199
200 #[test]
201 fn length_product_is_area() {
202 use crate::length::Meters;
203
204 let side = Meters::new(5.0);
205 let area: SquareMeters = side * side; assert_abs_diff_eq!(area.value(), 25.0, epsilon = 1e-12);
207 }
208
209 #[test]
210 #[cfg(feature = "customary")]
211 fn sqmile_to_sqkm() {
212 let a = SquareMiles::new(1.0);
213 let b: SquareKilometers = a.to();
214 assert_abs_diff_eq!(b.value(), 2.589_988_110_336, epsilon = 1e-6);
215 }
216
217 #[test]
218 fn sqcm_to_sqm() {
219 let a = SquareCentimeters::new(10_000.0);
220 let b: SquareMeters = a.to();
221 assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
222 }
223
224 #[test]
225 fn sqmm_to_sqcm() {
226 let a = SquareMillimeters::new(100.0);
227 let b: SquareCentimeters = a.to();
228 assert_abs_diff_eq!(b.value(), 1.0, epsilon = 1e-12);
229 }
230
231 #[test]
232 #[cfg(feature = "land-area")]
233 fn are_to_sqm() {
234 let a = Ares::new(1.0);
235 let b: SquareMeters = a.to();
236 assert_abs_diff_eq!(b.value(), 100.0, epsilon = 1e-12);
237 }
238
239 #[test]
240 #[cfg(feature = "customary")]
241 fn sqinch_to_sqcm() {
242 let a = SquareInches::new(1.0);
243 let b: SquareCentimeters = a.to();
244 assert_abs_diff_eq!(b.value(), 6.4516, epsilon = 1e-9);
246 }
247
248 #[test]
249 #[cfg(feature = "customary")]
250 fn sqyard_to_sqm() {
251 let a = SquareYards::new(1.0);
252 let b: SquareMeters = a.to();
253 assert_abs_diff_eq!(b.value(), 0.836_127_36, epsilon = 1e-9);
254 }
255
256 #[test]
257 fn roundtrip_sqcm_sqm() {
258 let original = SquareCentimeters::new(250.0);
259 let converted = original.to::<SquareMeter>();
260 let back = converted.to::<SquareCentimeter>();
261 assert_abs_diff_eq!(back.value(), original.value(), epsilon = 1e-10);
262 }
263
264 #[test]
265 fn sqrt_recovers_length_unit() {
266 use crate::length::{Meter, Meters};
267
268 let area = SquareMeters::new(36.0);
269 let side: crate::Quantity<Meter> = area.sqrt();
270 assert_abs_diff_eq!(side.value(), 6.0, epsilon = 1e-12);
271
272 let again: SquareMeters = side * side;
274 assert_abs_diff_eq!(again.value(), area.value(), epsilon = 1e-12);
275
276 let s = Meters::new(7.0);
278 let a = s * s;
279 let r: Meters = a.sqrt();
280 assert_abs_diff_eq!(r.value(), 7.0, epsilon = 1e-12);
281 }
282
283 #[test]
284 fn squared_unit_conversion_uses_squared_scale() {
285 let one_sqkm = SquareKilometers::new(1.0);
287 let in_sqm: SquareMeters = one_sqkm.to();
288 assert_abs_diff_eq!(in_sqm.value(), 1.0e6, epsilon = 1e-6);
289 }
290
291 #[test]
292 #[cfg(feature = "std")]
293 fn squared_unit_formatter_output() {
294 assert_eq!(format!("{}", SquareMeters::new(2.5)), "2.5 m·m");
296 assert_eq!(format!("{:e}", SquareMeters::new(1234.0)), "1.234e3 m·m");
298 }
299
300 #[test]
301 #[cfg(feature = "std")]
302 fn symbols_are_correct() {
303 assert_eq!(format!("{}", SquareMeters::new(1.0)), "1 m·m");
306 #[cfg(feature = "land-area")]
307 assert_eq!(Hectare::SYMBOL, "ha");
308 #[cfg(feature = "land-area")]
309 assert_eq!(Acre::SYMBOL, "ac");
310 #[cfg(feature = "customary")]
311 assert_eq!(SquareInch::SYMBOL, "in²");
312 }
313}