ifc_rs/units/
assignment.rs

1use std::fmt::Display;
2
3use ifc_rs_verify_derive::IfcVerify;
4
5use crate::{
6    id::IdOr,
7    ifc_type::{IfcType, IfcVerify},
8    parser::{list::IfcList, p_space_or_comment_surrounded, IFCParse, IFCParser},
9    prelude::*,
10};
11
12/// IfcUnitAssignment indicates a set of units which may be assigned. Within an
13/// IfcUnitAssigment each unit definition shall be unique; that is, there shall
14/// be no redundant unit definitions for the same unit type such as length unit
15/// or area unit. For currencies, there shall be only a single IfcMonetaryUnit
16/// within an IfcUnitAssignment.
17///
18/// https://standards.buildingsmart.org/IFC/DEV/IFC4_2/FINAL/HTML/link/ifcunitassignment.htm
19#[derive(IfcVerify)]
20pub struct UnitAssigment {
21    /// Units to be included within a unit assignment.
22    #[ifc_types(SiUnit, ConversionBasedUnit, DerivedUnit, MonetaryUnit)]
23    pub units: IfcList<Id>,
24}
25
26impl UnitAssigment {
27    pub fn new(units: impl IntoIterator<Item = IdOr<SiUnit>>, ifc: &mut IFC) -> Self {
28        Self {
29            units: IfcList(units.into_iter().map(|u| u.or_insert(ifc).id()).collect()),
30        }
31    }
32}
33
34impl IFCParse for UnitAssigment {
35    fn parse<'a>() -> impl IFCParser<'a, Self> {
36        winnow::seq! {
37            Self {
38                _: p_space_or_comment_surrounded("IFCUNITASSIGNMENT("),
39
40                units: IfcList::parse(),
41
42                _: p_space_or_comment_surrounded(");"),
43            }
44        }
45    }
46}
47
48impl Display for UnitAssigment {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(f, "IFCUNITASSIGNMENT({});", self.units)
51    }
52}
53
54impl IfcType for UnitAssigment {}
55
56#[cfg(test)]
57mod test {
58    use winnow::Parser;
59
60    use super::UnitAssigment;
61    use crate::parser::IFCParse;
62
63    #[test]
64    fn rel_aggregates_round_trip() {
65        let example = "IFCUNITASSIGNMENT((#18,#19,#20));";
66
67        let unit_assignment: UnitAssigment = UnitAssigment::parse().parse(example).unwrap();
68        let str_unit_assignment = unit_assignment.to_string();
69
70        assert_eq!(example, str_unit_assignment);
71    }
72}