1use ifc_model::{EntityId, Value};
11
12use crate::error::{StyleError, StyleResult};
13use crate::view::Record;
14
15mod layer;
16mod resolution;
17mod styled_item;
18
19pub use layer::PresentationStyleAssignment;
20pub use resolution::{ResolvedStyle, StyleSource};
21pub use styled_item::StyledItem;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum PresentationStyleMember {
26 Style(EntityId),
28 Null,
30}
31
32pub(crate) fn presentation_style_members(
33 record: Record<'_, '_>,
34 attribute: &'static str,
35 minimum: usize,
36) -> StyleResult<Vec<PresentationStyleMember>> {
37 let value = record.value(attribute)?;
38 let Value::List(items) = value.unwrap_typed() else {
39 return Err(record.invalid(attribute, value));
40 };
41 if items.len() < minimum {
42 return Err(StyleError::InvalidValue {
43 entity: record.entity.type_name.to_string(),
44 id: record.id,
45 attribute,
46 value: format!("{} member(s), expected at least {minimum}", items.len()),
47 });
48 }
49
50 items
51 .iter()
52 .map(|item| match item {
53 Value::Ref(target) => {
54 record.check_reference(*target, "IfcPresentationStyle")?;
55 Ok(PresentationStyleMember::Style(*target))
56 }
57 Value::Typed { type_name, value }
58 if type_name.eq_ignore_ascii_case("IFCNULLSTYLE")
59 && matches!(value.as_ref(), Value::Enum(member) if member.eq_ignore_ascii_case("NULL")) =>
60 {
61 Ok(PresentationStyleMember::Null)
62 }
63 _ => Err(record.invalid(attribute, item)),
64 })
65 .collect()
66}