speki_core/card/
basecard.rs

1use super::*;
2use crate::{audio::AudioId, card_provider::CardProvider, CardProperty, CardRefType};
3use either::Either;
4use ledgerstore::{ItemReference, Ledger, LedgerItem, LedgerType, PropertyCache};
5use omtrent::TimeStamp;
6use serde::{Deserialize, Serialize, Serializer};
7use std::{collections::HashSet, fmt::Display, str::FromStr};
8
9pub type CardId = Uuid;
10
11/// Text which might contain card references.
12#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Ord, PartialOrd)]
13pub struct TextData(Vec<Either<String, TextLink>>);
14
15impl From<String> for TextData {
16    fn from(value: String) -> Self {
17        Self::from_raw(&value)
18    }
19}
20
21impl TextData {
22    pub fn extend(&mut self, other: Self) {
23        for cmp in other.0 {
24            self.0.push(cmp);
25        }
26    }
27
28    pub fn push_link(&mut self, id: CardId, alias: Option<String>) {
29        let link = TextLink { id, alias };
30        self.0.push(Either::Right(link));
31    }
32
33    pub fn push_string(&mut self, s: String) {
34        self.0.push(Either::Left(s));
35    }
36
37    pub fn is_empty(&self) -> bool {
38        self.0.is_empty()
39    }
40
41    pub fn inner(&self) -> &Vec<Either<String, TextLink>> {
42        &self.0
43    }
44
45    pub fn inner_mut(&mut self) -> &mut Vec<Either<String, TextLink>> {
46        &mut self.0
47    }
48
49    pub fn evaluate(&self, provider: &CardProvider) -> String {
50        let mut out = String::new();
51
52        for cmp in &self.0 {
53            match cmp {
54                Either::Left(s) => out.push_str(&s),
55                Either::Right(TextLink { id, alias }) => match alias {
56                    Some(alias) => out.push_str(&alias),
57                    None => match provider.load(*id) {
58                        Some(card) => out.push_str(&card.name),
59                        None => out.push_str("<invalid card ref>"),
60                    },
61                },
62            }
63        }
64
65        out
66    }
67
68    pub fn card_ids(&self) -> Vec<CardId> {
69        let mut out = vec![];
70
71        for cmp in &self.0 {
72            match cmp {
73                Either::Left(_) => {}
74                Either::Right(TextLink { id, .. }) => out.push(*id),
75            }
76        }
77
78        out
79    }
80
81    pub fn from_raw(input: &str) -> Self {
82        let mut result = Vec::new();
83        let mut buffer = String::new();
84        let mut chars = input.chars().peekable();
85
86        while let Some(c) = chars.next() {
87            if c == '[' && chars.peek() == Some(&'[') {
88                chars.next(); // consume the second '['
89
90                // Push any text before this link
91                if !buffer.is_empty() {
92                    result.push(Either::Left(std::mem::take(&mut buffer)));
93                }
94
95                // Parse until closing "]]"
96                let mut link_buf = String::new();
97                while let Some(ch) = chars.next() {
98                    if ch == ']' && chars.peek() == Some(&']') {
99                        chars.next(); // consume second ']'
100                        break;
101                    } else {
102                        link_buf.push(ch);
103                    }
104                }
105
106                let parts: Vec<&str> = link_buf.splitn(2, '|').collect();
107                let (id_str, alias_opt) = if parts.len() == 2 {
108                    (parts[0], Some(parts[1].to_string()))
109                } else {
110                    (parts[0], None)
111                };
112
113                match id_str.parse::<CardId>() {
114                    Ok(id) => result.push(Either::Right(TextLink {
115                        id,
116                        alias: alias_opt,
117                    })),
118                    Err(_) => result.push(Either::Left(format!("[[{}]]", link_buf))),
119                }
120            } else {
121                buffer.push(c);
122            }
123        }
124
125        if !buffer.is_empty() {
126            result.push(Either::Left(buffer));
127        }
128
129        Self(result)
130    }
131
132    pub fn to_raw(&self) -> String {
133        let mut out = String::new();
134
135        for cmp in &self.0 {
136            let s = match cmp {
137                Either::Left(s) => s.to_string(),
138                Either::Right(TextLink { id, alias }) => match alias {
139                    Some(alias) => format!("[[{id}|{alias}]]"),
140                    None => format!("[[{id}]]"),
141                },
142            };
143
144            out.push_str(&s);
145        }
146
147        out
148    }
149}
150
151#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
152pub struct TextLink {
153    pub id: CardId,
154    pub alias: Option<String>,
155}
156
157impl TextLink {
158    pub fn new(id: CardId) -> Self {
159        Self { id, alias: None }
160    }
161}
162
163impl Serialize for TextData {
164    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
165    where
166        S: Serializer,
167    {
168        serializer.serialize_str(&self.to_raw())
169    }
170}
171
172impl<'de> Deserialize<'de> for TextData {
173    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
174    where
175        D: Deserializer<'de>,
176    {
177        let s = String::deserialize(deserializer)?;
178        Ok(TextData::from_raw(&s))
179    }
180}
181
182pub type AttributeId = Uuid;
183
184/*
185
186ok lets say
187
188the backtype has to be an instance of programming function where codebase == rust.
189hmm it feels kinda recursive in a way.. like can we make infinite
190
191
192InstanceValue {
193instance_of: {programming_function}
194constraints: vec![
195    InstanceFilter{
196        attr: Codebase
197        constraint:Card({rust})
198}]
199}
200
201
202ok lets see, another one, all cards of type male whose father was born in germany after 1960
203
204InstanceValue {
205    instance_of: {male}
206    constraints: vec![
207        AttrFilter{
208            attr: birth_date
209            constraint: ValueOf::TsAfter(1960)
210        },
211        AttrFilter{
212            attr: birthplace
213            constraint: ValueOf::Card({germany})
214        },
215    ]
216}
217
218
219ok lets see, another one, all cards of type female whose mother was born in europe before 1945
220
221InstanceValue {
222    instance_of: {female}
223    constraints: vec![
224        AttrFilter{
225            attr: birth_date
226            constraint: ValueOf::TsBefore(1945)
227        },
228        AttrFilter{
229            attr: birthplace
230            constraint: ValueOf::InstanceOfClass( InstanceValue {
231                instance_of: {country},
232                constraints: vec![AttrFilter {
233                    attr: continent,
234                    constraint: ValueOf::Card(europe)
235                }]
236            })
237        },
238    ]
239}
240
241
242/// To ensure that a certain attribute has a certain value
243struct AttrFilter {
244    attr: Attrv2,
245    constraint: ValueOf,
246}
247
248struct InstanceValue {
249    instance_of: CardId,
250    constraints: Vec<AttrFilter>,
251}
252
253/// like a filter to verify that the backside type/value is correct
254enum ValueOf {
255    Ts,                  // any timestamp
256    TsBefore(TimeStamp), //timestamp before given time
257    TsAfter(TimeStamp),  //timestamp after given time
258    InstanceOfClass(InstanceValue),
259    Card(CardId),
260}
261
262*/
263
264#[derive(PartialEq, Debug, Clone, Serialize, Hash, Eq, Ord, PartialOrd)]
265pub enum AttrBackType {
266    InstanceOfClass(CardId),
267    TimeStamp,
268    Boolean,
269}
270
271impl<'de> Deserialize<'de> for AttrBackType {
272    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
273    where
274        D: Deserializer<'de>,
275    {
276        let value = Value::deserialize(deserializer)?;
277
278        // Try to deserialize directly as Uuid
279        if let Ok(uuid) = Uuid::deserialize(&value) {
280            return Ok(AttrBackType::InstanceOfClass(uuid));
281        }
282
283        // Try deserializing as the new enum using a helper
284        #[derive(Deserialize)]
285        enum Helper {
286            InstanceOfClass(CardId),
287            TimeStamp,
288            Boolean,
289        }
290
291        let helper: Helper = serde_json::from_value(value).map_err(serde::de::Error::custom)?;
292        match helper {
293            Helper::InstanceOfClass(id) => Ok(AttrBackType::InstanceOfClass(id)),
294            Helper::TimeStamp => Ok(AttrBackType::TimeStamp),
295            Helper::Boolean => Ok(AttrBackType::Boolean),
296        }
297    }
298}
299
300/// An attribute of a class is pre-made questions that can be asked about any of the classes' instances.
301/// For example, all instances of `Person` can have the quesiton "when was {} born?"
302///
303/// Instances refer to both direct instances of the class, and instances of any sub-classes of the class.
304#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialOrd, Ord)]
305pub struct Attrv2 {
306    pub id: AttributeId,
307    pub pattern: String,
308    pub back_type: Option<AttrBackType>,
309}
310
311pub enum BackSideConstraint {
312    Card { ty: Option<CardId> },
313}
314
315#[derive(PartialEq, Debug, Clone, Serialize, Deserialize, Hash, Eq)]
316pub enum CardType {
317    /// A specific instance of a class
318    /// For example, the instance might be Elvis Presley where the concept would be "Person"
319    Instance {
320        name: TextData,
321        #[serde(default, skip_serializing_if = "Option::is_none")]
322        back: Option<BackSide>,
323        class: CardId,
324    },
325    Normal {
326        front: TextData,
327        back: BackSide,
328    },
329    Unfinished {
330        front: TextData,
331    },
332    /// An attribute describes a specific instance of a class. For example the class Person can have attribute "when was {} born?"
333    /// this will be applied to all instances of the class and its subclasses
334    Attribute {
335        attribute: AttributeId,
336        back: BackSide,
337        instance: CardId,
338    },
339
340    /// A class, which is something that has specific instances of it, but is not a single thing in itself.
341    /// A class might also have sub-classes, for example, the class chemical element has a sub-class isotope
342    Class {
343        name: TextData,
344        #[serde(default, skip_serializing_if = "Option::is_none")]
345        back: Option<BackSide>,
346        #[serde(default, skip_serializing_if = "Option::is_none")]
347        parent_class: Option<CardId>,
348        #[serde(default, skip_serializing_if = "Option::is_none")]
349        default_question: Option<TextData>,
350        #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
351        attrs: BTreeSet<Attrv2>,
352    },
353
354    /// A statement is a fact which cant easily be represented with a flashcard,
355    /// because asking the question implies the answer.
356    ///
357    /// For example, "Can the anglerfish produce light?" is a dumb question because it's so rare for animals
358    /// to produce light that the question wouldn't have been asked if it wasn't true.
359    ///
360    /// For these questions we use a statementcard which will simply state the fact without asking you. We still
361    /// need this card for dependency management since other questions might rely on you knowing this fact.
362    /// Knowledge of these kinda facts will instead be measured indirectly with questions about this property
363    ///
364    /// More formal definition of when a statement card is used:
365    ///
366    /// 1. It represents a property of an instance or sub-class.
367    /// 2. The set of the class it belongs to is large
368    /// 3. The property in that set is rare, but not unique
369    Statement {
370        front: TextData,
371    },
372
373    /// gotta figure out if i want this to be a thing in itself or it can be handled with just attributes of an event class
374    Event {
375        front: TextData,
376        start_time: TimeStamp,
377        end_time: Option<TimeStamp>,
378        parent_event: Option<CardId>,
379    },
380}
381
382impl CardType {
383    pub fn class(&self) -> Option<CardId> {
384        match self {
385            CardType::Instance { class, .. } => Some(*class),
386            CardType::Normal { .. } => None,
387            CardType::Unfinished { .. } => None,
388            CardType::Attribute { .. } => None,
389            CardType::Class { parent_class, .. } => *parent_class,
390            CardType::Statement { .. } => None,
391            CardType::Event { .. } => None,
392        }
393    }
394
395    pub fn backside(&self) -> Option<&BackSide> {
396        match self {
397            CardType::Instance {
398                back: Some(back), ..
399            } => {
400                if back.is_empty_text() {
401                    None
402                } else {
403                    Some(back)
404                }
405            }
406            CardType::Instance { back: None, .. } => None,
407            CardType::Normal { back, .. } => Some(back),
408            CardType::Unfinished { .. } => None,
409            CardType::Attribute { back, .. } if !back.is_empty_text() => Some(back),
410            CardType::Attribute { back, .. } => Some(back),
411            CardType::Class {
412                back: Some(back), ..
413            } if !back.is_empty_text() => Some(back),
414            CardType::Class {
415                back: Some(back), ..
416            } => Some(back),
417            CardType::Class { back: None, .. } => None,
418            CardType::Statement { .. } => None,
419            CardType::Event { .. } => None,
420        }
421    }
422
423    pub fn raw_front(&self) -> String {
424        match self.clone() {
425            CardType::Instance { name, .. } => name.to_raw(),
426            CardType::Normal { front, .. } => front.to_raw(),
427            CardType::Unfinished { front } => front.to_raw(),
428            CardType::Attribute { .. } => "attr card".to_string(),
429            CardType::Class { name, .. } => name.to_raw(),
430            CardType::Statement { front } => front.to_raw(),
431            CardType::Event { front, .. } => front.to_raw(),
432        }
433    }
434
435    pub fn raw_back(&self) -> String {
436        self.backside().map(|x| x.to_string()).unwrap_or_default()
437    }
438
439    pub async fn get_dependencies(&self) -> BTreeSet<CardId> {
440        match self {
441            CardType::Instance { class, back, .. } => {
442                let mut dependencies: BTreeSet<CardId> = Default::default();
443                dependencies.insert(*class);
444                dependencies.extend(
445                    back.clone()
446                        .map(|x| x.dependencies())
447                        .unwrap_or_default()
448                        .iter(),
449                );
450                dependencies
451            }
452            CardType::Normal { .. } => Default::default(),
453            CardType::Unfinished { .. } => Default::default(),
454            CardType::Attribute { back, instance, .. } => {
455                let mut dependencies: BTreeSet<CardId> = Default::default();
456                dependencies.insert(*instance);
457                dependencies.extend(back.dependencies().iter());
458                dependencies
459            }
460            CardType::Class {
461                back, parent_class, ..
462            } => {
463                let mut dependencies: BTreeSet<CardId> = Default::default();
464                dependencies.extend(back.as_ref().map(|x| x.dependencies()).unwrap_or_default());
465                if let Some(id) = parent_class {
466                    dependencies.insert(*id);
467                }
468                dependencies
469            }
470            CardType::Statement { .. } => Default::default(),
471            CardType::Event { .. } => todo!(),
472        }
473    }
474
475    pub fn name_fixed_ledger(&self) -> TextData {
476        match self {
477            CardType::Instance { name, .. } => name.clone(),
478            CardType::Normal { front, .. } => front.clone(),
479            CardType::Unfinished { front, .. } => front.clone(),
480            CardType::Attribute { .. } => {
481                panic!()
482            }
483            CardType::Class { name, .. } => name.clone(),
484            CardType::Statement { front, .. } => front.clone(),
485            CardType::Event { front, .. } => front.clone(),
486        }
487    }
488
489    pub fn name(&self, provider: &CardProvider) -> TextData {
490        match self {
491            CardType::Instance { name, .. } => name.clone(),
492            CardType::Normal { front, .. } => front.clone(),
493            CardType::Unfinished { front, .. } => front.clone(),
494            CardType::Attribute {
495                attribute,
496                instance,
497                ..
498            } => {
499                let class: CardId = provider
500                    .providers
501                    .cards
502                    .get_prop_cache(PropertyCache::new(
503                        CardProperty::Attr,
504                        attribute.to_string(),
505                    ))
506                    .into_iter()
507                    .next()
508                    .unwrap();
509
510                let class = provider.load(class).unwrap();
511                let attr = class.get_attr(*attribute).unwrap();
512                let instance = provider.load(*instance).unwrap().name_textdata();
513                let instance = instance.to_raw();
514
515                let new = attr.pattern.replace("{}", &instance);
516
517                TextData::from_raw(&new)
518            }
519            CardType::Class { name, .. } => name.clone(),
520            CardType::Statement { front, .. } => front.clone(),
521            CardType::Event { front, .. } => front.clone(),
522        }
523    }
524
525    pub fn display_front(&self, provider: &CardProvider) -> TextData {
526        match self {
527            CardType::Instance {
528                name, class, back, ..
529            } => {
530                let (class_name, default_question) =
531                    match provider.providers.cards.load(*class).data {
532                        CardType::Class {
533                            default_question,
534                            name,
535                            ..
536                        } => (name, default_question),
537                        other => {
538                            dbg!(class);
539                            dbg!(other);
540                            panic!();
541                        }
542                    };
543
544                let thename = &name.evaluate(provider);
545                let class_name = &class_name.evaluate(provider);
546
547                match default_question {
548                    Some(q) => {
549                        let s = q.evaluate(provider).replace("{}", thename);
550                        TextData::from_raw(&s)
551                    }
552
553                    None => {
554                        if back.is_some() {
555                            let s = format!("{thename} ({class_name})");
556                            TextData::from_raw(&s)
557                        } else {
558                            name.clone()
559                        }
560                    }
561                }
562            }
563            CardType::Normal { front, .. } => front.clone(),
564            CardType::Unfinished { front, .. } => front.clone(),
565            CardType::Attribute {
566                attribute,
567                instance,
568                ..
569            } => {
570                let class: CardId = provider
571                    .providers
572                    .cards
573                    .get_prop_cache(PropertyCache::new(
574                        CardProperty::Attr,
575                        attribute.to_string(),
576                    ))
577                    .into_iter()
578                    .next()
579                    .unwrap();
580
581                let class = provider.load(class).unwrap();
582
583                let attr = class.get_attr(*attribute).unwrap();
584
585                let new = if attr.pattern.contains("{}") {
586                    attr.pattern.replace("{}", &format!("[[{instance}]]"))
587                } else {
588                    format!("[[{instance}]]: {}", attr.pattern)
589                };
590
591                TextData::from_raw(&new)
592            }
593            CardType::Class {
594                name, parent_class, ..
595            } => match parent_class {
596                Some(class) => {
597                    let mut name = name.clone();
598
599                    if self.backside().is_some() {
600                        name.push_string(" ( ".to_string());
601                        name.push_link(*class, None);
602                        name.push_string(")".to_string());
603                    }
604
605                    name
606                }
607                None => name.clone(),
608            },
609            CardType::Statement { front, .. } => front.clone(),
610            CardType::Event { front, .. } => front.clone(),
611        }
612    }
613
614    pub fn type_name(&self) -> &str {
615        match self {
616            CardType::Unfinished { .. } => "unfinished",
617            CardType::Statement { .. } => "statement",
618            CardType::Attribute { .. } => "attribute",
619            CardType::Instance { .. } => "instance",
620            CardType::Normal { .. } => "normal",
621            CardType::Class { .. } => "class",
622            CardType::Event { .. } => "event",
623        }
624    }
625
626    /// This is mainly just so i dont forget to update the CType when the AnyType changes
627    pub fn fieldless(&self) -> CType {
628        match self {
629            CardType::Instance { .. } => CType::Instance,
630            CardType::Normal { .. } => CType::Normal,
631            CardType::Unfinished { .. } => CType::Unfinished,
632            CardType::Attribute { .. } => CType::Attribute,
633            CardType::Class { .. } => CType::Class,
634            CardType::Statement { .. } => CType::Statement,
635            CardType::Event { .. } => CType::Event,
636        }
637    }
638
639    pub fn parent_class(&self) -> Option<CardId> {
640        match self {
641            CardType::Class { parent_class, .. } => *parent_class,
642            _ => None,
643        }
644    }
645
646    pub fn is_class(&self) -> bool {
647        matches!(self, Self::Class { .. })
648    }
649    pub fn is_instance(&self) -> bool {
650        matches!(self, Self::Instance { .. })
651    }
652    pub fn is_finished(&self) -> bool {
653        !matches!(self, Self::Unfinished { .. })
654    }
655}
656
657fn bool_is_false(b: &bool) -> bool {
658    *b == false
659}
660
661#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq)]
662pub struct RawCard {
663    pub id: Uuid,
664    /// The context of which the name of the card makes sense. For example, instead of writing `kubernetes node`, you can just
665    /// write `node` and put kubernetes as the namespace. This avoids unnecessarily long names for disambiguation.
666    #[serde(default, skip_serializing_if = "Option::is_none")]
667    pub namespace: Option<CardId>,
668    pub data: CardType,
669    #[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
670    pub explicit_dependencies: BTreeSet<Uuid>,
671    #[serde(default, skip_serializing_if = "bool_is_false")]
672    pub trivial: bool,
673    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
674    pub tags: BTreeMap<String, String>,
675    #[serde(default, skip_serializing_if = "Option::is_none")]
676    pub front_audio: Option<AudioId>,
677    #[serde(default, skip_serializing_if = "Option::is_none")]
678    pub back_audio: Option<AudioId>,
679}
680
681impl RawCard {
682    pub fn cache_front(&self, ledger: &Ledger<RawCard>) -> String {
683        match self.data.clone() {
684            CardType::Instance { name, .. } => name.to_raw(),
685            CardType::Normal { front, .. } => front.to_raw(),
686            CardType::Unfinished { front } => front.to_raw(),
687            CardType::Attribute {
688                attribute: _,
689                instance,
690                ..
691            } => {
692                dbg!(&self);
693                let attr = self.get_attr_rec(ledger.to_owned()).unwrap();
694
695                let instance = ledger.load(instance).data.name_fixed_ledger();
696                let instance = instance.to_raw();
697
698                let new = attr.pattern.replace("{}", &instance);
699                new
700            }
701            CardType::Class { name, .. } => name.to_raw(),
702            CardType::Statement { front } => front.to_raw(),
703            CardType::Event { front, .. } => front.to_raw(),
704        }
705    }
706
707    /// Returns the class this card belongs to (if any)
708    pub fn parent_class(&self) -> Option<CardId> {
709        match self.data {
710            CardType::Instance { class, .. } => Some(class),
711            CardType::Normal { .. } => None,
712            CardType::Unfinished { .. } => None,
713            CardType::Attribute { .. } => None,
714            CardType::Class { parent_class, .. } => parent_class,
715            CardType::Statement { .. } => None,
716            CardType::Event { .. } => None,
717        }
718    }
719
720    pub fn ref_mut_backside(&mut self) -> Option<&mut BackSide> {
721        match &mut self.data {
722            CardType::Instance { back, .. } => back.as_mut(),
723            CardType::Normal { back, .. } => Some(back),
724            CardType::Unfinished { .. } => None,
725            CardType::Attribute { back, .. } => Some(back),
726            CardType::Class { back, .. } => back.as_mut(),
727            CardType::Statement { .. } => None,
728            CardType::Event { .. } => None,
729        }
730    }
731
732    pub fn ref_backside(&self) -> Option<&BackSide> {
733        match &self.data {
734            CardType::Instance { back, .. } => back.as_ref(),
735            CardType::Normal { back, .. } => Some(back),
736            CardType::Unfinished { .. } => None,
737            CardType::Attribute { back, .. } => Some(back),
738            CardType::Class { back, .. } => back.as_ref(),
739            CardType::Statement { .. } => None,
740            CardType::Event { .. } => None,
741        }
742    }
743
744    fn attrs(&self) -> BTreeSet<Attrv2> {
745        if let CardType::Class { ref attrs, .. } = &self.data {
746            return attrs.clone();
747        } else {
748            Default::default()
749        }
750    }
751
752    pub fn get_attr(&self, id: AttributeId) -> Option<Attrv2> {
753        if let CardType::Class { ref attrs, .. } = &self.data {
754            attrs.iter().find(|attr| attr.id == id).cloned()
755        } else {
756            None
757        }
758    }
759
760    pub fn get_attr_rec(&self, ledger: Ledger<RawCard>) -> Option<Attrv2> {
761        let CardType::Attribute {
762            attribute,
763            instance,
764            ..
765        } = &self.data
766        else {
767            return None;
768        };
769
770        let mut card: Self = ledger.load(*instance);
771
772        while let Some(parent) = card.parent_class() {
773            card = ledger.load(parent);
774            if let Some(attr) = card.get_attr(*attribute) {
775                return Some(attr);
776            }
777        }
778
779        None
780    }
781
782    pub fn set_backside(mut self, new_back: BackSide) -> Self {
783        let data = match self.data.clone() {
784            x @ CardType::Event { .. } => x,
785            CardType::Instance {
786                name,
787                back: _,
788                class,
789            } => CardType::Instance {
790                name,
791                back: Some(new_back),
792                class,
793            },
794            x @ CardType::Statement { .. } => x,
795
796            CardType::Normal { front, back: _ } => CardType::Normal {
797                front,
798                back: new_back,
799            },
800            CardType::Unfinished { front } => CardType::Normal {
801                front,
802                back: new_back,
803            },
804            CardType::Attribute {
805                attribute,
806                instance: concept_card,
807                back: _,
808            } => CardType::Attribute {
809                attribute,
810                back: new_back,
811                instance: concept_card,
812            },
813            CardType::Class {
814                name,
815                back: _,
816                parent_class,
817                default_question,
818                attrs,
819            } => CardType::Class {
820                name,
821                back: Some(new_back),
822                parent_class,
823                default_question,
824                attrs,
825            },
826        };
827
828        self.data = data;
829        self
830    }
831}
832
833pub fn bigrams(text: &str) -> Vec<[char; 2]> {
834    normalize_string(text)
835        .chars()
836        .collect::<Vec<_>>()
837        .windows(2)
838        .map(|w| [w[0], w[1]])
839        .collect()
840}
841
842pub fn normalize_string(str: &str) -> String {
843    deunicode::deunicode(str)
844        .to_lowercase()
845        .chars()
846        .filter(|c| c.is_ascii_alphanumeric())
847        .collect()
848}
849
850use fancy_regex::Regex;
851fn resolve_text(txt: String, ledger: &Ledger<RawCard>, re: &Regex) -> String {
852    let uuids: Vec<CardId> = re
853        .find_iter(&txt)
854        .filter_map(Result::ok)
855        .map(|m| m.as_str().parse().unwrap())
856        .collect();
857
858    let mut s: String = re.replace_all(&txt, "").to_string();
859    for id in uuids {
860        let card = ledger.load(id);
861        let txt = card.cache_front(ledger);
862        s.push_str(&resolve_text(txt, ledger, re));
863    }
864
865    s
866}
867
868/// replaces all uuids on frontside of card with the frontside of the card referenced by uuid.
869/// just appends it, doesn't preserve order, this is just to collect bigrams.
870fn resolve_card(card: &RawCard, ledger: &Ledger<RawCard>) -> String {
871    let uuid_regex = Regex::new(
872        r"\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b",
873    )
874    .unwrap();
875
876    resolve_text(card.cache_front(ledger), ledger, &uuid_regex)
877}
878
879#[derive(Debug)]
880pub enum CardError {
881    InstanceOfNonClass,
882    AttributeOfNonInstance,
883    MissingAttribute,
884    DefaultQuestionNotClass,
885    WrongCardType,
886    AnswerMustBeCard,
887    AnswerMustBeTime,
888    AnswerMustBeBool,
889    SubClassOfNonClass,
890    BackTypeMustBeClass,
891}
892
893fn instance_is_of_type(instance: CardId, ty: CardId, ledger: &LedgerType<RawCard>) -> bool {
894    let instance = ledger.load(instance);
895    assert!(instance.data.is_instance());
896
897    get_parent_classes(ty, ledger)
898        .into_iter()
899        .find(|class| class.id == ty)
900        .is_some()
901}
902
903fn get_parent_classes(class: CardId, ledger: &LedgerType<RawCard>) -> Vec<RawCard> {
904    let class = ledger.load(class);
905    let mut classes: Vec<RawCard> = vec![class.clone()];
906    assert!(class.data.is_class());
907    let mut parent_class = class.parent_class();
908
909    while let Some(parent) = parent_class {
910        let class = ledger.load(parent);
911        assert!(class.data.is_class());
912        parent_class = class.parent_class();
913        classes.push(class);
914    }
915
916    classes
917}
918
919fn get_attributes(class: CardId, ledger: &LedgerType<RawCard>) -> Vec<Attrv2> {
920    let mut out: Vec<Attrv2> = vec![];
921    for class in get_parent_classes(class, ledger) {
922        if let CardType::Class { attrs, .. } = class.data {
923            out.extend(attrs);
924        } else {
925            panic!()
926        }
927    }
928    out
929}
930
931impl LedgerItem for RawCard {
932    type Error = CardError;
933    type Key = CardId;
934    type RefType = CardRefType;
935    type PropertyType = CardProperty;
936    type Modifier = CardAction;
937
938    fn validate(&self, ledger: &LedgerType<Self>) -> Result<(), Self::Error> {
939        match &self.data {
940            CardType::Instance {
941                name: _,
942                back: _,
943                class,
944            } => {
945                if !ledger.load(*class).data.is_class() {
946                    return Err(CardError::InstanceOfNonClass);
947                }
948            }
949
950            CardType::Normal { front: _, back: _ } => {}
951            CardType::Unfinished { front: _ } => {}
952            CardType::Attribute {
953                attribute,
954                back: attr_back,
955                instance,
956            } => {
957                let CardType::Instance { name, back, class } = ledger.load(*instance).data else {
958                    return Err(CardError::InstanceOfNonClass);
959                };
960
961                let class = {
962                    let class = ledger.load(class);
963                    if !class.data.is_class() {
964                        return Err(CardError::InstanceOfNonClass);
965                    }
966                    class
967                };
968
969                let Some(Attrv2 { back_type, .. }) = get_attributes(class.id, &ledger)
970                    .into_iter()
971                    .find(|attr| attr.id == *attribute)
972                else {
973                    return Err(CardError::MissingAttribute);
974                };
975
976                match back_type {
977                    Some(AttrBackType::Boolean) => {
978                        if !matches!(attr_back, BackSide::Bool(_)) {
979                            return Err(CardError::AnswerMustBeBool);
980                        }
981                    }
982                    Some(AttrBackType::TimeStamp) => {
983                        if !matches!(attr_back, BackSide::Time(_)) {
984                            return Err(CardError::AnswerMustBeTime);
985                        }
986                    }
987                    Some(AttrBackType::InstanceOfClass(back_class)) => {
988                        if let BackSide::Card(answer) = attr_back {
989                            if !instance_is_of_type(*answer, back_class, &ledger) {
990                                return Err(CardError::WrongCardType);
991                            }
992                        } else {
993                            dbg!(name);
994                            dbg!(&back);
995                            dbg!(&attr_back);
996                            dbg!(ledger.load(*instance));
997                            dbg!(self);
998                            let err = dbg!(CardError::AnswerMustBeCard);
999                            return Err(err);
1000                        }
1001                    }
1002                    None => {}
1003                }
1004            }
1005            CardType::Class {
1006                name: _,
1007                back: _,
1008                parent_class,
1009                default_question: _,
1010                attrs,
1011            } => {
1012                if let Some(parent) = parent_class {
1013                    if !ledger.load(*parent).data.is_class() {
1014                        return Err(CardError::SubClassOfNonClass);
1015                    }
1016                }
1017
1018                for attr in attrs {
1019                    if let Some(AttrBackType::InstanceOfClass(back_type)) = attr.back_type {
1020                        if !ledger.load(back_type).data.is_class() {
1021                            return Err(CardError::BackTypeMustBeClass);
1022                        }
1023                    }
1024                }
1025            }
1026            CardType::Statement { front: _ } => {}
1027            // todo lol
1028            CardType::Event {
1029                front: _,
1030                start_time: _,
1031                end_time: _,
1032                parent_event: _,
1033            } => {}
1034        }
1035
1036        Ok(())
1037    }
1038
1039    fn ref_cache(&self) -> HashSet<ItemReference<Self>> {
1040        let from = self.id;
1041        let mut out: HashSet<ItemReference<Self>> = Default::default();
1042
1043        if let Some(ns) = self.namespace {
1044            out.insert(ItemReference::new(from, ns, CardRefType::LinkRef));
1045        }
1046
1047        for dep in &self.explicit_dependencies {
1048            out.insert(ItemReference::new(
1049                from,
1050                *dep,
1051                CardRefType::ExplicitDependency,
1052            ));
1053        }
1054
1055        match &self.data {
1056            CardType::Normal { front, .. } => {
1057                for id in front.card_ids() {
1058                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1059                }
1060            }
1061            CardType::Unfinished { front, .. } => {
1062                for id in front.card_ids() {
1063                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1064                }
1065            }
1066            CardType::Instance { name, class, .. } => {
1067                for id in name.card_ids() {
1068                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1069                }
1070
1071                out.insert(ItemReference::new(
1072                    from,
1073                    *class,
1074                    CardRefType::ClassOfInstance,
1075                ));
1076            }
1077            CardType::Attribute { instance, .. } => {
1078                out.insert(ItemReference::new(
1079                    from,
1080                    *instance,
1081                    CardRefType::InstanceOfAttribute,
1082                ));
1083            }
1084            CardType::Class {
1085                name,
1086                default_question,
1087                parent_class,
1088                ..
1089            } => {
1090                for id in name.card_ids() {
1091                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1092                }
1093
1094                if let Some(def) = default_question {
1095                    for id in def.card_ids() {
1096                        out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1097                    }
1098                }
1099
1100                if let Some(class) = parent_class {
1101                    out.insert(ItemReference::new(from, *class, CardRefType::ParentClass));
1102                }
1103            }
1104            CardType::Statement { front, .. } => {
1105                for id in front.card_ids() {
1106                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1107                }
1108            }
1109            CardType::Event { front, .. } => {
1110                for id in front.card_ids() {
1111                    out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1112                }
1113            }
1114        };
1115
1116        if let Some(back) = &self.data.backside() {
1117            match back {
1118                BackSide::Text(txt) => {
1119                    for id in txt.card_ids() {
1120                        out.insert(ItemReference::new(from, id, CardRefType::LinkRef));
1121                    }
1122                }
1123                BackSide::Card(id) => {
1124                    out.insert(ItemReference::new(from, *id, CardRefType::LinkRef));
1125                }
1126                BackSide::List(ids) => {
1127                    for id in ids {
1128                        out.insert(ItemReference::new(from, *id, CardRefType::LinkRef));
1129                    }
1130                }
1131                BackSide::Time(_) => {}
1132                BackSide::Trivial => {}
1133                BackSide::Invalid => {}
1134                BackSide::Bool(_) => {}
1135            }
1136        }
1137
1138        out
1139    }
1140
1141    fn properties_cache(&self, cache: &Ledger<Self>) -> HashSet<PropertyCache<Self>> {
1142        let mut out: HashSet<PropertyCache<Self>> = Default::default();
1143
1144        let resolved_text = resolve_card(self, &cache);
1145
1146        for bigram in bigrams(&resolved_text) {
1147            let value = format!("{}{}", bigram[0], bigram[1]);
1148            let prop = PropertyCache {
1149                property: CardProperty::Bigram,
1150                value,
1151            };
1152            out.insert(prop);
1153        }
1154
1155        if self.trivial {
1156            out.insert(PropertyCache {
1157                property: CardProperty::Trivial,
1158                value: self.trivial.to_string(),
1159            });
1160        }
1161
1162        match &self.data {
1163            CardType::Normal { .. } => {}
1164            CardType::Unfinished { .. } => {}
1165            CardType::Instance { .. } => {}
1166            CardType::Attribute { attribute, .. } => {
1167                let prop = PropertyCache {
1168                    property: CardProperty::AttrId,
1169                    value: attribute.to_string(),
1170                };
1171                out.insert(prop);
1172            }
1173            CardType::Class { attrs, .. } => {
1174                for attr in attrs {
1175                    let prop = PropertyCache {
1176                        property: CardProperty::Attr,
1177                        value: attr.id.to_string(),
1178                    };
1179                    out.insert(prop);
1180                }
1181            }
1182            CardType::Statement { .. } => {}
1183            CardType::Event { .. } => {}
1184        };
1185
1186        let val = format!("{:?}", self.data.fieldless());
1187        let prop = PropertyCache {
1188            property: CardProperty::CardType,
1189            value: val,
1190        };
1191
1192        out.insert(prop);
1193
1194        out
1195    }
1196
1197    fn new_default(id: CardId) -> Self {
1198        Self {
1199            id,
1200            namespace: None,
1201            data: CardType::Unfinished {
1202                front: TextData::from_raw("uninit"),
1203            },
1204            trivial: false,
1205            tags: Default::default(),
1206            explicit_dependencies: Default::default(),
1207            front_audio: Default::default(),
1208            back_audio: Default::default(),
1209        }
1210    }
1211
1212    fn inner_run_event(mut self, event: CardAction) -> Result<Self, Self::Error> {
1213        match event {
1214            CardAction::SetDefaultQuestion(default) => match &mut self.data {
1215                CardType::Class {
1216                    ref mut default_question,
1217                    ..
1218                } => *default_question = default.map(|s| TextData::from_raw(&s)),
1219                _ => return Err(CardError::DefaultQuestionNotClass),
1220            },
1221            CardAction::SetBackTime(ts) => {
1222                self = self.set_backside(BackSide::Time(ts));
1223            }
1224            CardAction::SetTrivial(flag) => {
1225                self.trivial = flag;
1226            }
1227            CardAction::SetBackBool(b) => {
1228                let backside = BackSide::Bool(b);
1229                self = self.set_backside(backside);
1230            }
1231            CardAction::SetFrontAudio(audio) => {
1232                self.front_audio = audio;
1233            }
1234            CardAction::SetBackAudio(audio) => {
1235                self.back_audio = audio;
1236            }
1237            CardAction::UpsertCard(ty) => {
1238                self.data = ty;
1239            }
1240            CardAction::SetNamespace(ns) => {
1241                self.namespace = ns;
1242            }
1243            CardAction::AddDependency(dependency) => {
1244                self.explicit_dependencies.insert(dependency);
1245            }
1246            CardAction::RemoveDependency(dependency) => {
1247                self.explicit_dependencies.remove(&dependency);
1248            }
1249            CardAction::SetBackRef(reff) => {
1250                let backside = BackSide::Card(reff);
1251                self = self.set_backside(backside);
1252            }
1253            CardAction::InsertAttr(attrv2) => {
1254                if let CardType::Class { ref mut attrs, .. } = self.data {
1255                    attrs.insert(attrv2);
1256                } else {
1257                    panic!("expeted class");
1258                }
1259            }
1260            CardAction::RemoveAttr(attr_id) => {
1261                if let CardType::Class { ref mut attrs, .. } = self.data {
1262                    dbg!(&attrs);
1263                    let attr_len = attrs.len();
1264                    attrs.retain(|attr| attr.id != attr_id);
1265                    assert_eq!(attr_len - 1, attrs.len());
1266                    dbg!(&attrs);
1267                } else {
1268                    panic!("expeted class");
1269                }
1270            }
1271            CardAction::SetParentClass(new_parent_class) => {
1272                if let CardType::Class {
1273                    ref mut parent_class,
1274                    ..
1275                } = self.data
1276                {
1277                    *parent_class = new_parent_class;
1278                } else {
1279                    panic!("expeted class");
1280                }
1281            }
1282            CardAction::SetInstanceClass(instance_class) => {
1283                if let CardType::Instance { ref mut class, .. } = self.data {
1284                    *class = instance_class;
1285                } else {
1286                    panic!("expected instance");
1287                }
1288            }
1289            CardAction::AttributeType {
1290                attribute,
1291                back,
1292                instance,
1293            } => {
1294                self.data = CardType::Attribute {
1295                    attribute,
1296                    back,
1297                    instance,
1298                };
1299            }
1300            CardAction::NormalType { front, back } => {
1301                self.data = CardType::Normal { front, back };
1302            }
1303            CardAction::InstanceType { front, class } => {
1304                let back = self.ref_backside().cloned();
1305                self.data = CardType::Instance {
1306                    name: front,
1307                    back,
1308                    class,
1309                };
1310            }
1311            CardAction::StatementType { front } => {
1312                self.data = CardType::Statement { front };
1313            }
1314            CardAction::ClassType { front } => {
1315                self.data = CardType::Class {
1316                    name: front,
1317                    back: self.ref_backside().cloned(),
1318                    parent_class: self.parent_class(),
1319                    default_question: None,
1320                    attrs: self.attrs(),
1321                };
1322            }
1323            CardAction::UnfinishedType { front } => {
1324                self.data = CardType::Unfinished { front };
1325            }
1326            CardAction::EventType { front, start_time } => {
1327                self.data = CardType::Event {
1328                    front,
1329                    start_time,
1330                    end_time: None,
1331                    parent_event: None,
1332                };
1333            }
1334            CardAction::SetBackside(back_side) => match &mut self.data {
1335                CardType::Instance { ref mut back, .. } => {
1336                    *back = back_side;
1337                }
1338                CardType::Normal { ref mut back, .. } => {
1339                    if let Some(back_side) = back_side {
1340                        *back = back_side;
1341                    } else {
1342                        panic!("normal cards require backside");
1343                    }
1344                }
1345                CardType::Unfinished { .. } => {
1346                    panic!("nope, unfinishde");
1347                }
1348                CardType::Attribute { ref mut back, .. } => {
1349                    if let Some(back_side) = back_side {
1350                        *back = back_side;
1351                    } else {
1352                        panic!("attr cards require backside");
1353                    }
1354                }
1355                CardType::Class { ref mut back, .. } => {
1356                    *back = back_side;
1357                }
1358                CardType::Statement { .. } => panic!("no back on statement"),
1359                CardType::Event { .. } => panic!("no back on event"),
1360            },
1361            CardAction::InsertAttrs(new_attrs) => {
1362                if let CardType::Class { ref mut attrs, .. } = self.data {
1363                    *attrs = new_attrs;
1364                } else {
1365                    panic!("expected class");
1366                }
1367            }
1368            CardAction::SetFront(new_front) => match &mut self.data {
1369                CardType::Instance { ref mut name, .. } => {
1370                    *name = new_front;
1371                }
1372                CardType::Normal { front, .. } => {
1373                    *front = new_front;
1374                }
1375                CardType::Unfinished { front } => {
1376                    *front = new_front;
1377                }
1378                CardType::Attribute { .. } => {
1379                    panic!("cant set frontside on attr cards")
1380                }
1381                CardType::Class { name, .. } => {
1382                    *name = new_front;
1383                }
1384                CardType::Statement { front } => *front = new_front,
1385                CardType::Event { front, .. } => {
1386                    *front = new_front;
1387                }
1388            },
1389        };
1390
1391        let implicit_deps: BTreeSet<Uuid> = {
1392            let mut all = self.ref_cache();
1393            all.retain(|ItemReference { ty, .. }| match ty {
1394                CardRefType::ExplicitDependency => false,
1395                _ => true,
1396            });
1397
1398            all.into_iter().map(|x| x.to).collect()
1399        };
1400
1401        self.explicit_dependencies = self
1402            .explicit_dependencies
1403            .difference(&implicit_deps)
1404            .cloned()
1405            .collect();
1406
1407        Ok(self)
1408    }
1409
1410    fn item_id(&self) -> CardId {
1411        self.id
1412    }
1413}
1414
1415#[derive(Serialize, Ord, PartialOrd, Eq, Hash, PartialEq, Debug, Clone)]
1416pub enum BackSide {
1417    Bool(bool),
1418    Text(TextData),
1419    Card(CardId),
1420    List(Vec<CardId>),
1421    Time(TimeStamp),
1422    Trivial, // Answer is obvious, used when card is more of a dependency anchor
1423    Invalid, // A reference card was deleted
1424}
1425
1426#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, Hash, PartialEq, Debug, Clone)]
1427pub enum BarSide {
1428    Bool(bool),
1429    Text(String),
1430    Card(CardId),
1431    List(Vec<CardId>),
1432    Time(TimeStamp),
1433    Trivial,
1434    Invalid,
1435}
1436
1437impl From<BarSide> for BackSide {
1438    fn from(value: BarSide) -> Self {
1439        match value {
1440            BarSide::Text(val) => BackSide::Text(val.into()),
1441            BarSide::Bool(val) => BackSide::Bool(val),
1442            BarSide::Card(val) => BackSide::Card(val),
1443            BarSide::List(val) => BackSide::List(val),
1444            BarSide::Time(val) => BackSide::Time(val),
1445            BarSide::Trivial => BackSide::Trivial,
1446            BarSide::Invalid => BackSide::Invalid,
1447        }
1448    }
1449}
1450
1451impl Default for BackSide {
1452    fn default() -> Self {
1453        Self::Text(Default::default())
1454    }
1455}
1456
1457impl From<String> for BackSide {
1458    fn from(s: String) -> Self {
1459        if let Ok(uuid) = Uuid::parse_str(&s) {
1460            Self::Card(uuid)
1461        } else if let Ok(timestamp) = TimeStamp::from_str(&s) {
1462            Self::Time(timestamp)
1463        } else if s.as_str() == Self::INVALID_STR {
1464            Self::Invalid
1465        } else {
1466            Self::Text(s.into())
1467        }
1468    }
1469}
1470
1471impl BackSide {
1472    pub const INVALID_STR: &'static str = "__INVALID__";
1473
1474    pub fn is_empty_text(&self) -> bool {
1475        if let Self::Text(s) = self {
1476            s.is_empty()
1477        } else {
1478            false
1479        }
1480    }
1481
1482    pub fn is_time(&self) -> bool {
1483        matches!(self, Self::Time(_))
1484    }
1485
1486    pub fn is_text(&self) -> bool {
1487        matches!(self, Self::Text(_))
1488    }
1489
1490    pub fn is_ref(&self) -> bool {
1491        matches!(self, Self::Card(_))
1492    }
1493
1494    pub fn as_timestamp(&self) -> Option<TimeStamp> {
1495        if let Self::Time(ts) = self {
1496            Some(ts.to_owned())
1497        } else {
1498            None
1499        }
1500    }
1501
1502    pub fn as_bool(&self) -> Option<bool> {
1503        if let Self::Bool(b) = self {
1504            Some(*b)
1505        } else {
1506            None
1507        }
1508    }
1509
1510    pub fn as_card(&self) -> Option<CardId> {
1511        if let Self::Card(card) = self {
1512            Some(*card)
1513        } else {
1514            None
1515        }
1516    }
1517
1518    pub fn to_string(&self) -> String {
1519        match self {
1520            BackSide::Bool(b) => b.to_string(),
1521            BackSide::Text(s) => s.to_raw(),
1522            BackSide::Card(id) => id.to_string(),
1523            BackSide::List(ids) => format!("{ids:?}"),
1524            BackSide::Time(ts) => dbg!(ts.serialize()),
1525            BackSide::Trivial => "<trivial>".to_string(),
1526            BackSide::Invalid => "<invalid>".to_string(),
1527        }
1528    }
1529
1530    pub fn dependencies(&self) -> BTreeSet<CardId> {
1531        let mut set = BTreeSet::default();
1532        match self {
1533            BackSide::Text(s) => {
1534                set.extend(s.card_ids());
1535            }
1536            BackSide::Card(card_id) => {
1537                let _ = set.insert(*card_id);
1538            }
1539            BackSide::List(vec) => {
1540                set.extend(vec.iter());
1541            }
1542            BackSide::Time(_) => {}
1543            BackSide::Trivial => {}
1544            BackSide::Invalid => {}
1545            BackSide::Bool(_) => {}
1546        }
1547
1548        set
1549    }
1550}
1551
1552impl<'de> Deserialize<'de> for BackSide {
1553    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1554    where
1555        D: Deserializer<'de>,
1556    {
1557        let value = Value::deserialize(deserializer)?;
1558
1559        match value {
1560            Value::Array(arr) => {
1561                let mut ids = Vec::new();
1562                for item in arr {
1563                    if let Value::String(ref s) = item {
1564                        if let Ok(uuid) = Uuid::parse_str(s) {
1565                            ids.push(uuid);
1566                        } else {
1567                            return Err(serde::de::Error::custom("Invalid UUID in array"));
1568                        }
1569                    } else {
1570                        return Err(serde::de::Error::custom("Expected string in array"));
1571                    }
1572                }
1573                Ok(BackSide::List(ids))
1574            }
1575            Value::Bool(_) => Ok(BackSide::Trivial),
1576            Value::String(s) => Ok(s.into()),
1577            val => Ok(serde_json::from_value::<BarSide>(val).unwrap().into()),
1578        }
1579    }
1580}
1581
1582#[derive(Serialize, Deserialize, Debug, Clone, Default)]
1583pub struct Config;
1584
1585#[derive(
1586    Serialize, Deserialize, Debug, Clone, Default, Copy, Eq, PartialEq, Hash, PartialOrd, Ord,
1587)]
1588#[serde(rename_all = "lowercase")]
1589pub enum CType {
1590    Instance,
1591    #[default]
1592    Normal,
1593    Unfinished,
1594    Attribute,
1595    Class,
1596    Statement,
1597    Event,
1598}
1599
1600impl Display for CType {
1601    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1602        write!(f, "{:?}", self)
1603    }
1604}
1605
1606impl CType {
1607    pub fn short_form(&self) -> &'static str {
1608        match self {
1609            CType::Instance => "I",
1610            CType::Normal => "N",
1611            CType::Attribute => "A",
1612            CType::Class => "C",
1613            CType::Unfinished => "U",
1614            CType::Statement => "S",
1615            CType::Event => "E",
1616        }
1617    }
1618}