moduforge_model/
schema.rs1use super::attrs::Attrs;
2use super::content::ContentMatch;
3use super::mark_type::{MarkSpec, MarkType};
4use super::node_type::{NodeSpec, NodeType};
5use serde::Serialize;
6use serde_json::Value;
7use std::any::Any;
8use std::collections::HashMap;
9use std::error::Error;
10use std::sync::{Arc, Mutex};
11#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize)]
14pub struct Attribute {
15 pub has_default: bool,
16 pub default: Option<Value>,
17}
18
19impl Attribute {
20 pub(crate) fn new(options: AttributeSpec) -> Self {
22 Attribute {
23 has_default: options.default.is_some(),
24 default: options.default,
25 }
26 }
27 pub fn is_required(&self) -> bool {
30 !self.has_default
31 }
32}
33#[derive(Clone, Debug)]
36pub struct Schema {
37 pub spec: SchemaSpec,
39 pub top_node_type: Option<NodeType>,
41 pub cached: Arc<Mutex<HashMap<String, Arc<dyn Any + Send + Sync>>>>,
43 pub nodes: HashMap<String, NodeType>,
45 pub marks: HashMap<String, MarkType>,
47}
48impl PartialEq for Schema {
49 fn eq(
50 &self,
51 other: &Self,
52 ) -> bool {
53 self.spec == other.spec
54 && self.top_node_type == other.top_node_type
55 && self.nodes == other.nodes
56 && self.marks == other.marks
57 }
58}
59impl Eq for Schema {}
60impl Schema {
61 pub fn new(spec: SchemaSpec) -> Self {
63 let mut instance_spec = SchemaSpec {
64 nodes: HashMap::new(),
65 marks: HashMap::new(),
66 top_node: spec.top_node,
67 };
68 for (key, value) in spec.nodes {
70 instance_spec.nodes.insert(key, value);
71 }
72 for (key, value) in spec.marks {
73 instance_spec.marks.insert(key, value);
74 }
75 Schema {
76 spec: instance_spec,
77 top_node_type: None,
78 cached: Arc::new(Mutex::new(HashMap::new())),
79 nodes: HashMap::new(),
80 marks: HashMap::new(),
81 }
82 }
83 pub fn compile(
86 instance_spec: SchemaSpec
87 ) -> Result<Schema, Box<dyn Error>> {
88 let mut schema: Schema = Schema::new(instance_spec);
89 let nodes: HashMap<String, NodeType> =
90 NodeType::compile(schema.spec.nodes.clone());
91 let marks = MarkType::compile(schema.spec.marks.clone());
92 let mut content_expr_cache = HashMap::new();
93 let mut updated_nodes = HashMap::new();
94 for (prop, type_) in &nodes {
95 if marks.contains_key(prop) {
96 return Err(format!("{} 不能既是节点又是标记", prop).into());
97 }
98
99 let content_expr = type_.spec.content.as_deref().unwrap_or("");
100 let mark_expr = type_.spec.marks.as_deref();
101
102 let content_match = content_expr_cache
103 .entry(content_expr.to_string())
104 .or_insert_with(|| {
105 ContentMatch::parse(content_expr.to_string(), &nodes)
106 })
107 .clone();
108
109 let mark_set = match mark_expr {
110 Some("_") => None,
111 Some(expr) => {
112 let marks_result = gather_marks(
113 &schema,
114 expr.split_whitespace().collect(),
115 );
116 match marks_result {
117 Ok(marks) => Some(marks.into_iter().cloned().collect()), Err(e) => return Err(e.into()),
119 }
120 },
121 None => None,
122 };
123
124 let mut node = type_.clone();
125 node.content_match = Some(content_match);
126 node.mark_set = mark_set;
127 updated_nodes.insert(prop.clone(), node);
128 }
129 schema.nodes = updated_nodes;
130 schema.marks = marks;
131 schema.top_node_type = match schema.nodes.get(
132 &schema.spec.top_node.clone().unwrap_or_else(|| "doc".to_string()),
133 ) {
134 Some(node) => Some(node.clone()),
135 None => {
136 return Err("未找到顶级节点类型定义".to_string().into());
137 },
138 };
139
140 Ok(schema)
141 }
142}
143#[derive(Clone, PartialEq, Eq, Debug)]
146pub struct SchemaSpec {
147 pub nodes: HashMap<String, NodeSpec>,
148 pub marks: HashMap<String, MarkSpec>,
149 pub top_node: Option<String>,
150}
151
152pub fn default_attrs(
157 attrs: &HashMap<String, Attribute>
158) -> Option<HashMap<String, Value>> {
159 let mut defaults = HashMap::new();
160
161 for (attr_name, attr) in attrs {
162 if let Some(default) = &attr.default {
163 defaults.insert(attr_name.clone(), default.clone());
164 } else {
165 return None;
166 }
167 }
168
169 Some(defaults)
170}
171#[derive(Clone, PartialEq, Debug, Eq, Hash, Serialize)]
173pub struct AttributeSpec {
174 pub default: Option<Value>,
176}
177fn gather_marks<'a>(
180 schema: &'a Schema,
181 marks: Vec<&'a str>,
182) -> Result<Vec<&'a MarkType>, String> {
183 let mut found = Vec::new();
184
185 for name in marks {
186 if let Some(mark) = schema.marks.get(name) {
187 found.push(mark);
188 } else {
189 let mut ok = None;
190 for mark_ref in schema.marks.values() {
191 if name == "_"
192 || mark_ref.spec.group.as_ref().is_some_and(|group| {
193 group.split_whitespace().any(|g| g == name)
194 })
195 {
196 found.push(mark_ref);
197 ok = Some(mark_ref);
198 break;
199 }
200 }
201 if ok.is_none() {
202 return Err(format!("未知的标记类型: '{}'", name));
203 }
204 }
205 }
206 Ok(found)
207}
208pub fn compute_attrs(
211 attrs: &HashMap<String, Attribute>,
212 value: Option<&HashMap<String, Value>>,
213) -> Attrs {
214 let mut built = Attrs::default();
215
216 for (name, attr) in attrs {
217 let given = value.and_then(|v| v.get(name));
218
219 let given = match given {
220 Some(val) => val.clone(),
221 None => {
222 if attr.has_default {
223 attr.default.clone().unwrap_or_else(|| {
224 panic!("没有为属性提供默认值 {}", name)
225 })
226 } else {
227 Value::Null
228 }
229 },
230 };
231
232 built[&name] = given;
233 }
234
235 built
236}