Skip to main content

ifc_cost/mutation/
draft.rs

1//! Domain-shaped drafts for the bounded IFC4 cost authoring slice.
2
3use ifc_model::EntityId;
4
5use super::datetime::DateTimeValue;
6use crate::ArithmeticOperator;
7
8/// Supported `IfcCostItemTypeEnum` values.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum CostItemType {
12    /// A user-defined kind; `ObjectType` is then required.
13    UserDefined,
14    /// No more specific predefined kind is asserted.
15    NotDefined,
16}
17impl CostItemType {
18    pub(crate) const fn token(self) -> &'static str {
19        match self {
20            Self::UserDefined => "USERDEFINED",
21            Self::NotDefined => "NOTDEFINED",
22        }
23    }
24}
25
26/// Supported `IfcCostScheduleTypeEnum` values.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28#[non_exhaustive]
29pub enum CostScheduleType {
30    /// A budget.
31    Budget,
32    /// A cost plan.
33    CostPlan,
34    /// An estimate.
35    Estimate,
36    /// A tender.
37    Tender,
38    /// A priced bill of quantities.
39    PricedBillOfQuantities,
40    /// An unpriced bill of quantities.
41    UnpricedBillOfQuantities,
42    /// A schedule of rates.
43    ScheduleOfRates,
44    /// A user-defined kind; `ObjectType` is then required.
45    UserDefined,
46    /// No more specific predefined kind is asserted.
47    NotDefined,
48}
49impl CostScheduleType {
50    pub(crate) const fn token(self) -> &'static str {
51        match self {
52            Self::Budget => "BUDGET",
53            Self::CostPlan => "COSTPLAN",
54            Self::Estimate => "ESTIMATE",
55            Self::Tender => "TENDER",
56            Self::PricedBillOfQuantities => "PRICEDBILLOFQUANTITIES",
57            Self::UnpricedBillOfQuantities => "UNPRICEDBILLOFQUANTITIES",
58            Self::ScheduleOfRates => "SCHEDULEOFRATES",
59            Self::UserDefined => "USERDEFINED",
60            Self::NotDefined => "NOTDEFINED",
61        }
62    }
63}
64
65/// The unambiguous applied-value shape supported by bounded authoring.
66#[derive(Debug, Clone, Copy)]
67#[non_exhaustive]
68pub enum CostValueKind<'a> {
69    /// One finite `IfcMonetaryMeasure`.
70    Monetary(f64),
71    /// An ordered composition of already existing or staged cost values.
72    Components {
73        /// Arithmetic operation applied by consumers.
74        operator: ArithmeticOperator,
75        /// Ordered `IfcCostValue` references; at least one is required.
76        components: &'a [EntityId],
77    },
78}
79
80#[derive(Debug, Clone, Copy)]
81/// Draft for one supported `IfcCostValue`.
82#[non_exhaustive]
83pub struct CostValueDraft<'a> {
84    /// Optional display name.
85    pub name: Option<&'a str>,
86    /// Optional description.
87    pub description: Option<&'a str>,
88    /// Optional date from which the value applies: `IfcDate` text in IFC4
89    /// and IFC4X3, an `IfcDateTimeSelect` record form in IFC2X3.
90    pub applicable_date: Option<DateTimeValue<'a>>,
91    /// Optional date through which the value is fixed, in the same forms.
92    pub fixed_until_date: Option<DateTimeValue<'a>>,
93    /// Optional cost category (`Category`; IFC2X3's `CostType`, which it
94    /// requires).
95    pub category: Option<&'a str>,
96    /// Optional applicability condition.
97    pub condition: Option<&'a str>,
98    /// Supported scalar or composed value shape.
99    pub kind: CostValueKind<'a>,
100}
101impl CostValueDraft<'_> {
102    #[must_use]
103    /// Create a scalar monetary draft with no optional metadata.
104    pub fn monetary(amount: f64) -> Self {
105        Self {
106            kind: CostValueKind::Monetary(amount),
107            ..Self::default()
108        }
109    }
110}
111impl Default for CostValueDraft<'_> {
112    fn default() -> Self {
113        Self {
114            name: None,
115            description: None,
116            applicable_date: None,
117            fixed_until_date: None,
118            category: None,
119            condition: None,
120            kind: CostValueKind::Monetary(0.0),
121        }
122    }
123}
124
125#[derive(Debug, Clone, Copy, Default)]
126/// Draft for a selected IFC4 `IfcCostItem`.
127#[non_exhaustive]
128pub struct CostItemDraft<'a> {
129    /// Compressed IFC `GlobalId`; validated before staging.
130    pub global_id: &'a str,
131    /// Optional display name.
132    pub name: Option<&'a str>,
133    /// Optional description.
134    pub description: Option<&'a str>,
135    /// Optional user-defined object type.
136    pub object_type: Option<&'a str>,
137    /// Optional domain identifier.
138    pub identification: Option<&'a str>,
139    /// Optional bounded item type.
140    pub predefined_type: Option<CostItemType>,
141    /// Ordered existing or earlier-staged `IfcCostValue` references.
142    pub cost_values: &'a [EntityId],
143}
144#[derive(Debug, Clone, Copy, Default)]
145/// Draft for an IFC4 `IfcCostSchedule`.
146#[non_exhaustive]
147pub struct CostScheduleDraft<'a> {
148    /// Compressed IFC `GlobalId`; validated before staging.
149    pub global_id: &'a str,
150    /// Optional display name.
151    pub name: Option<&'a str>,
152    /// Optional description.
153    pub description: Option<&'a str>,
154    /// Optional user-defined object type.
155    pub object_type: Option<&'a str>,
156    /// Optional domain identifier.
157    pub identification: Option<&'a str>,
158    /// Optional bounded schedule type.
159    pub predefined_type: Option<CostScheduleType>,
160    /// Optional schedule status.
161    pub status: Option<&'a str>,
162    /// Optional submission date: ISO 8601 `IfcDateTime` text in IFC4 and
163    /// IFC4X3, an `IfcDateTimeSelect` record form in IFC2X3.
164    pub submitted_on: Option<DateTimeValue<'a>>,
165    /// Optional update date, in the same form as `submitted_on`.
166    pub update_date: Option<DateTimeValue<'a>>,
167}
168#[derive(Debug, Clone, Copy)]
169/// Draft for ordered cost-item nesting through `IfcRelNests`.
170#[non_exhaustive]
171pub struct NestingDraft<'a> {
172    /// Compressed IFC `GlobalId`; validated before staging.
173    pub global_id: &'a str,
174    /// Parent `IfcCostItem`.
175    pub parent: EntityId,
176    /// Non-empty, duplicate-free ordered child list.
177    pub children: &'a [EntityId],
178}
179#[derive(Debug, Clone, Copy)]
180/// Draft assigning cost items to a cost schedule.
181#[non_exhaustive]
182pub struct ScheduleAssignmentDraft<'a> {
183    /// Compressed IFC `GlobalId`; validated before staging.
184    pub global_id: &'a str,
185    /// Relating `IfcCostSchedule`.
186    pub schedule: EntityId,
187    /// Non-empty, duplicate-free related `IfcCostItem` set.
188    pub items: &'a [EntityId],
189}
190
191impl<'a> CostValueDraft<'a> {
192    /// Sets the display name.
193    #[must_use]
194    pub fn name(mut self, value: &'a str) -> Self {
195        self.name = Some(value);
196        self
197    }
198
199    /// Sets the description.
200    #[must_use]
201    pub fn description(mut self, value: &'a str) -> Self {
202        self.description = Some(value);
203        self
204    }
205
206    /// Sets the date from which the value applies: text, or an IFC2X3
207    /// record form.
208    #[must_use]
209    pub fn applicable_date(mut self, value: impl Into<DateTimeValue<'a>>) -> Self {
210        self.applicable_date = Some(value.into());
211        self
212    }
213
214    /// Sets the date through which the value is fixed: text, or an IFC2X3
215    /// record form.
216    #[must_use]
217    pub fn fixed_until_date(mut self, value: impl Into<DateTimeValue<'a>>) -> Self {
218        self.fixed_until_date = Some(value.into());
219        self
220    }
221
222    /// Sets the cost category.
223    #[must_use]
224    pub fn category(mut self, value: &'a str) -> Self {
225        self.category = Some(value);
226        self
227    }
228
229    /// Sets the applicability condition.
230    #[must_use]
231    pub fn condition(mut self, value: &'a str) -> Self {
232        self.condition = Some(value);
233        self
234    }
235
236    /// Sets the scalar or composed value shape.
237    #[must_use]
238    pub fn kind(mut self, value: CostValueKind<'a>) -> Self {
239        self.kind = value;
240        self
241    }
242}
243
244impl<'a> CostItemDraft<'a> {
245    /// Starts a draft for an `IfcCostItem` with its `GlobalId` and every optional
246    /// attribute unset.
247    #[must_use]
248    pub fn new(global_id: &'a str) -> Self {
249        Self {
250            global_id,
251            ..Self::default()
252        }
253    }
254
255    /// Sets the display name.
256    #[must_use]
257    pub fn name(mut self, value: &'a str) -> Self {
258        self.name = Some(value);
259        self
260    }
261
262    /// Sets the description.
263    #[must_use]
264    pub fn description(mut self, value: &'a str) -> Self {
265        self.description = Some(value);
266        self
267    }
268
269    /// Sets the user-defined object type.
270    #[must_use]
271    pub fn object_type(mut self, value: &'a str) -> Self {
272        self.object_type = Some(value);
273        self
274    }
275
276    /// Sets the domain identifier.
277    #[must_use]
278    pub fn identification(mut self, value: &'a str) -> Self {
279        self.identification = Some(value);
280        self
281    }
282
283    /// Sets the item type.
284    #[must_use]
285    pub fn predefined_type(mut self, value: CostItemType) -> Self {
286        self.predefined_type = Some(value);
287        self
288    }
289
290    /// Sets the ordered `IfcCostValue` references.
291    #[must_use]
292    pub fn cost_values(mut self, value: &'a [EntityId]) -> Self {
293        self.cost_values = value;
294        self
295    }
296}
297
298impl<'a> CostScheduleDraft<'a> {
299    /// Starts a draft for an `IfcCostSchedule` with its `GlobalId` and every optional
300    /// attribute unset.
301    #[must_use]
302    pub fn new(global_id: &'a str) -> Self {
303        Self {
304            global_id,
305            ..Self::default()
306        }
307    }
308
309    /// Sets the display name.
310    #[must_use]
311    pub fn name(mut self, value: &'a str) -> Self {
312        self.name = Some(value);
313        self
314    }
315
316    /// Sets the description.
317    #[must_use]
318    pub fn description(mut self, value: &'a str) -> Self {
319        self.description = Some(value);
320        self
321    }
322
323    /// Sets the user-defined object type.
324    #[must_use]
325    pub fn object_type(mut self, value: &'a str) -> Self {
326        self.object_type = Some(value);
327        self
328    }
329
330    /// Sets the domain identifier (IFC2X3 `ID`, required there).
331    #[must_use]
332    pub fn identification(mut self, value: &'a str) -> Self {
333        self.identification = Some(value);
334        self
335    }
336
337    /// Sets the schedule type.
338    #[must_use]
339    pub fn predefined_type(mut self, value: CostScheduleType) -> Self {
340        self.predefined_type = Some(value);
341        self
342    }
343
344    /// Sets the schedule status.
345    #[must_use]
346    pub fn status(mut self, value: &'a str) -> Self {
347        self.status = Some(value);
348        self
349    }
350
351    /// Sets the submission date.
352    #[must_use]
353    pub fn submitted_on(mut self, value: impl Into<DateTimeValue<'a>>) -> Self {
354        self.submitted_on = Some(value.into());
355        self
356    }
357
358    /// Sets the update date.
359    #[must_use]
360    pub fn update_date(mut self, value: impl Into<DateTimeValue<'a>>) -> Self {
361        self.update_date = Some(value.into());
362        self
363    }
364}
365
366impl<'a> NestingDraft<'a> {
367    /// Starts a draft nesting `children`, in order, under `parent`.
368    #[must_use]
369    pub const fn new(global_id: &'a str, parent: EntityId, children: &'a [EntityId]) -> Self {
370        Self {
371            global_id,
372            parent,
373            children,
374        }
375    }
376}
377
378impl<'a> ScheduleAssignmentDraft<'a> {
379    /// Starts a draft assigning `items` to `schedule`.
380    #[must_use]
381    pub const fn new(global_id: &'a str, schedule: EntityId, items: &'a [EntityId]) -> Self {
382        Self {
383            global_id,
384            schedule,
385            items,
386        }
387    }
388}