snomed_classify/skipped.rs
1//! Constructs `classify` recognizes but doesn't model, per
2//! `spec/13-classification.md`'s "Scope" section. Every occurrence is
3//! reported, never silently dropped without a trace.
4
5use std::fmt;
6
7use snomed_core::sctid::SctId;
8
9/// `#[non_exhaustive]` per `spec/rust-api-stability.md`: this enum grows
10/// every time a construct is recognized but not modeled, and a consumer
11/// only ever reports what it holds.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[non_exhaustive]
14pub enum SkippedConstruct {
15 /// A `ReflexiveObjectProperty` axiom — reflexivity isn't modeled.
16 ReflexiveProperty(SctId),
17 /// A `SubDataPropertyOf` axiom — data (concrete-value) property
18 /// hierarchy isn't modeled.
19 DataProperty(SctId),
20 /// A `DataHasValue` conjunct on `attribute`, dropped from whatever
21 /// intersection or existential filler it appeared in.
22 ConcreteValue { attribute: SctId },
23 /// A `SubObjectPropertyOf` whose sub-property is an
24 /// `ObjectPropertyChain` with no operands, naming the super-property
25 /// it would have implied. `snomed-owl`'s parser rejects this shape;
26 /// only a hand-built [`snomed_owl::Axiom`] can produce it.
27 EmptyRoleChain(SctId),
28 /// A stated axiom shape `necessary_normal_form` couldn't turn into a
29 /// `(type, value)` attribute pair — e.g. a role group or ungrouped
30 /// existential whose filler isn't a plain concept (spec/14). `concept`
31 /// is the named subject whose stated profile the shape appeared in.
32 UnmodeledAttributeShape { concept: SctId },
33}
34
35impl fmt::Display for SkippedConstruct {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 SkippedConstruct::ReflexiveProperty(id) => {
39 write!(f, "ReflexiveObjectProperty(:{id}) is not modeled")
40 }
41 SkippedConstruct::DataProperty(id) => {
42 write!(f, "SubDataPropertyOf involving :{id} is not modeled")
43 }
44 SkippedConstruct::ConcreteValue { attribute } => {
45 write!(
46 f,
47 "DataHasValue on attribute :{attribute} was dropped (concrete values aren't classified)"
48 )
49 }
50 SkippedConstruct::EmptyRoleChain(target) => {
51 write!(
52 f,
53 "an empty ObjectPropertyChain under :{target} implies nothing and was dropped"
54 )
55 }
56 SkippedConstruct::UnmodeledAttributeShape { concept } => {
57 write!(
58 f,
59 "a stated attribute of :{concept} has an unmodeled shape (not a plain concept filler) and was dropped from its necessary normal form"
60 )
61 }
62 }
63 }
64}