eure_document/data_model.rs
1use crate::document::node::NodeValue;
2use crate::prelude_internal::*;
3
4/// Data model of a document or a value in a document. Corresponds to the `$data-model` extension.
5#[derive(Debug, Clone, Copy, PartialEq, Default)]
6pub enum DataModel {
7 /// Serde compatible data model.
8 Rust,
9 /// JSON compatible data model.
10 Json,
11 /// Eure full data model including path.
12 #[default]
13 Eure,
14}
15
16#[derive(Debug, Clone, PartialEq, Default)]
17pub struct DataModelConfig {
18 pub data_model: DataModel,
19 pub variant_repr: VariantRepr,
20 pub number_key_repr: NumberKeyRepr,
21 pub tuple_key_repr: TupleKeyRepr,
22 pub boolean_key_repr: BooleanKeyRepr,
23 pub tuple_repr: TupleRepr,
24}
25
26#[derive(Debug, Clone, PartialEq, Default)]
27/// How to represent numeric keys in a data model that does not support numbers as object keys. Corresponds to the `$number-key-repr` extension.
28pub enum NumberKeyRepr {
29 /// Represent number as string.
30 String,
31 /// Error on conversion.
32 #[default]
33 Error,
34}
35
36#[derive(Debug, Clone, PartialEq, Default)]
37/// How to represent tuple keys in a data model that does not support tuples as object keys. Corresponds to the `$tuple-key-repr` extension.
38pub enum TupleKeyRepr {
39 /// Represent tuple as string. e.g. "(1,2,3)".
40 String,
41 /// Error on conversion.
42 #[default]
43 Error,
44}
45
46#[derive(Debug, Clone, PartialEq, Default)]
47/// How to represent boolean keys in a data model that does not support booleans as object keys. Corresponds to the `$boolean-key-repr` extension.
48pub enum BooleanKeyRepr {
49 /// Represent boolean as string. e.g. "true" or "false".
50 String,
51 /// Error on conversion.
52 #[default]
53 Error,
54}
55
56#[derive(Debug, Clone, PartialEq, Default)]
57/// How to represent tuples in a data model that does not support tuples. Corresponds to the `$tuple-repr` extension.
58pub enum TupleRepr {
59 /// Represent tuple as array. e.g. "[1,2,3]".
60 Array,
61 /// Represent tuple as number indexed object. e.g. `{0: 1, 1: 2, 2: 3}`. `{"0": 1, "1": 2, "2": 3}` if `NumberKeyRepr` is `String`.
62 NumberIndexedObject,
63 /// Error on conversion.
64 #[default]
65 Error,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
69/// How to represent variant in a data model. Corresponds to the `$variant-repr` extension.
70pub enum VariantRepr {
71 /// External tagging: {"variant-name": {...}}
72 External,
73
74 /// Internal tagging: {"type": "variant-name", ...fields...}
75 Internal { tag: String },
76
77 /// Adjacent tagging: {"type": "variant-name", "content": {...}}
78 Adjacent { tag: String, content: String },
79
80 /// Untagged: try all variants without structure-based matching.
81 /// This is the default when no `$variant-repr` is specified.
82 #[default]
83 Untagged,
84}
85
86impl VariantRepr {
87 /// Create a VariantRepr from $variant-repr annotation node
88 // FIXME: Use ParseDocument
89 pub fn from_annotation(doc: &EureDocument, node_id: NodeId) -> Option<Self> {
90 let node = doc.node(node_id);
91 match &node.content {
92 NodeValue::Primitive(PrimitiveValue::Text(t)) if t.as_str() == "untagged" => {
93 Some(VariantRepr::Untagged)
94 }
95 NodeValue::Map(map) => {
96 let tag =
97 map.0
98 .get(&ObjectKey::String("tag".to_string()))
99 .and_then(|&id| match &doc.node(id).content {
100 NodeValue::Primitive(PrimitiveValue::Text(t)) => {
101 Some(t.as_str().to_string())
102 }
103 _ => None,
104 });
105
106 let content = map
107 .0
108 .get(&ObjectKey::String("content".to_string()))
109 .and_then(|&id| match &doc.node(id).content {
110 NodeValue::Primitive(PrimitiveValue::Text(t)) => {
111 Some(t.as_str().to_string())
112 }
113 _ => None,
114 });
115
116 match (tag, content) {
117 (Some(tag), Some(content)) => Some(VariantRepr::Adjacent { tag, content }),
118 (Some(tag), None) => Some(VariantRepr::Internal { tag }),
119 _ => None,
120 }
121 }
122 _ => None,
123 }
124 }
125}
126
127/// How to represent text with non-plaintext language in a data model.
128///
129/// This controls how `Text` values with `Language::Other(lang)` are serialized
130/// to formats that don't natively support language-tagged text.
131///
132/// Corresponds to the `$text-repr` extension (formerly `$code-repr`).
133#[derive(Debug, Clone, PartialEq, Default)]
134pub enum TextRepr {
135 /// Markdown code block string.
136 /// e.g. "```rust\nfn main() { println!(\"Hello, world!\"); }\n```".
137 Markdown,
138 /// Content only string, discarding language information.
139 /// e.g. "fn main() { println!(\"Hello, world!\"); }".
140 String,
141 /// Object with language and content fields.
142 /// e.g. `{"language": "rust", "content": "fn main() { println!(\"Hello, world!\"); }"}`.
143 Object {
144 language_key: String,
145 content_key: String,
146 },
147 /// Error on conversion.
148 #[default]
149 Error,
150}