Skip to main content

tiptap_rusty_parser/
node.rs

1//! Core data model: [`Node`] and [`Mark`].
2//!
3//! Mirrors Tiptap's `JSONContent` interface. Schema-agnostic: any node/mark
4//! `type` is accepted and unknown JSON fields are preserved in `extra` for
5//! faithful roundtrip.
6
7use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor};
8use serde::ser::{SerializeMap, Serializer};
9use serde::{Deserialize, Serialize};
10use serde_json::{Map, Value};
11use std::fmt;
12use std::marker::PhantomData;
13
14/// A single Tiptap/ProseMirror node.
15///
16/// All structural fields are optional to faithfully distinguish "missing" from
17/// "empty" on roundtrip. Unknown top-level keys land in [`Node::extra`].
18///
19/// `attrs` and `extra` are boxed so the common attr-less, extra-less node stays
20/// small (one pointer each); `extra: None` and `Some(empty)` compare equal and
21/// serialize identically.
22///
23/// Serde: serialized as a JSON object with keys in the order `type`, `attrs`,
24/// `content`, `marks`, `text` (each only when `Some`), then `extra` in its own
25/// order. On deserialize, a `null` known field reads as `None`, a repeated
26/// known field is a `duplicate field` error, and a repeated unknown key keeps
27/// its first position with the last value.
28#[derive(Debug, Clone, Default)]
29pub struct Node {
30    /// Node type, e.g. `"doc"`, `"paragraph"`, `"text"`.
31    pub node_type: Option<String>,
32
33    /// Node attributes.
34    pub attrs: Option<Box<Map<String, Value>>>,
35
36    /// Child nodes.
37    pub content: Option<Vec<Node>>,
38
39    /// Marks applied to this node (typically text nodes).
40    pub marks: Option<Vec<Mark>>,
41
42    /// Text payload (text nodes only).
43    pub text: Option<String>,
44
45    /// Any unknown/extra top-level fields, preserved verbatim (`None` = none).
46    pub extra: Option<Box<Map<String, Value>>>,
47}
48
49/// A mark applied to a node (e.g. `bold`, `italic`, `link`).
50///
51/// Serde: `type` (required, string), then `attrs` (when `Some`), then `extra`;
52/// same `null`/duplicate rules as [`Node`].
53#[derive(Debug, Clone)]
54pub struct Mark {
55    /// Mark type, e.g. `"bold"`.
56    pub mark_type: String,
57
58    /// Mark attributes (e.g. `href` for a link).
59    pub attrs: Option<Box<Map<String, Value>>>,
60
61    /// Any unknown/extra fields, preserved verbatim (`None` = none).
62    pub extra: Option<Box<Map<String, Value>>>,
63}
64
65impl Mark {
66    /// Create a mark of `mark_type` with no attrs.
67    ///
68    /// ```
69    /// use tiptap_rusty_parser::Mark;
70    /// let m = Mark::new("bold");
71    /// assert_eq!(m.mark_type, "bold");
72    /// ```
73    #[inline]
74    pub fn new(mark_type: impl Into<String>) -> Self {
75        Mark {
76            mark_type: mark_type.into(),
77            attrs: None,
78            extra: None,
79        }
80    }
81
82    /// Builder: set one attr.
83    #[inline]
84    pub fn attr(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
85        self.attrs
86            .get_or_insert_with(Default::default)
87            .insert(key.into(), value.into());
88        self
89    }
90
91    /// Attrs map, if any.
92    #[inline]
93    pub fn attrs(&self) -> Option<&Map<String, Value>> {
94        self.attrs.as_deref()
95    }
96
97    /// Mutable attrs map, creating it if absent.
98    #[inline]
99    pub fn attrs_mut(&mut self) -> &mut Map<String, Value> {
100        self.attrs.get_or_insert_with(Default::default)
101    }
102
103    /// Unknown/extra fields, if any (may be `Some(empty)`).
104    #[inline]
105    pub fn extra(&self) -> Option<&Map<String, Value>> {
106        self.extra.as_deref()
107    }
108
109    /// Mutable extra map, creating it if absent.
110    #[inline]
111    pub fn extra_mut(&mut self) -> &mut Map<String, Value> {
112        self.extra.get_or_insert_with(Default::default)
113    }
114}
115
116impl Node {
117    /// Attrs map, if any.
118    #[inline]
119    pub fn attrs(&self) -> Option<&Map<String, Value>> {
120        self.attrs.as_deref()
121    }
122
123    /// Unknown/extra fields, if any (may be `Some(empty)`).
124    #[inline]
125    pub fn extra(&self) -> Option<&Map<String, Value>> {
126        self.extra.as_deref()
127    }
128
129    /// Mutable extra map, creating it if absent.
130    #[inline]
131    pub fn extra_mut(&mut self) -> &mut Map<String, Value> {
132        self.extra.get_or_insert_with(Default::default)
133    }
134
135    /// Extra field `key`.
136    #[inline]
137    pub fn extra_field(&self, key: &str) -> Option<&Value> {
138        self.extra.as_ref()?.get(key)
139    }
140
141    /// Remove extra field `key`, dropping the map once empty.
142    pub fn remove_extra(&mut self, key: &str) -> Option<Value> {
143        let m = self.extra.as_mut()?;
144        let prev = m.remove(key);
145        if m.is_empty() {
146            self.extra = None;
147        }
148        prev
149    }
150}
151
152/// `None` and `Some(empty)` are the same extra set.
153#[inline]
154pub(crate) fn extra_eq(
155    a: &Option<Box<Map<String, Value>>>,
156    b: &Option<Box<Map<String, Value>>>,
157) -> bool {
158    match (a, b) {
159        (None, None) => true,
160        (Some(x), Some(y)) => x == y,
161        (Some(m), None) | (None, Some(m)) => m.is_empty(),
162    }
163}
164
165impl PartialEq for Node {
166    #[inline]
167    fn eq(&self, o: &Node) -> bool {
168        self.node_type == o.node_type
169            && self.text == o.text
170            && self.attrs == o.attrs
171            && self.marks == o.marks
172            && extra_eq(&self.extra, &o.extra)
173            && self.content == o.content
174    }
175}
176
177impl PartialEq for Mark {
178    #[inline]
179    fn eq(&self, o: &Mark) -> bool {
180        self.mark_type == o.mark_type && self.attrs == o.attrs && extra_eq(&self.extra, &o.extra)
181    }
182}
183
184// Hand-written serde: one pass over the map, known keys straight into typed
185// fields, the rest into `extra`. Avoids `#[serde(flatten)]`, which buffers
186// every unknown entry through serde's private `Content` tree.
187
188/// Object key: a known field (matched without allocating) or an unknown key.
189enum Key {
190    Type,
191    Attrs,
192    Content,
193    Marks,
194    Text,
195    Other(String),
196}
197
198impl Key {
199    #[inline]
200    fn known(s: &str) -> Option<Key> {
201        Some(match s {
202            "type" => Key::Type,
203            "attrs" => Key::Attrs,
204            "content" => Key::Content,
205            "marks" => Key::Marks,
206            "text" => Key::Text,
207            _ => return None,
208        })
209    }
210}
211
212struct KeyVisitor;
213
214impl<'de> Visitor<'de> for KeyVisitor {
215    type Value = Key;
216
217    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
218        f.write_str("field identifier")
219    }
220
221    #[inline]
222    fn visit_str<E: de::Error>(self, v: &str) -> Result<Key, E> {
223        Ok(Key::known(v).unwrap_or_else(|| Key::Other(v.to_owned())))
224    }
225
226    #[inline]
227    fn visit_string<E: de::Error>(self, v: String) -> Result<Key, E> {
228        Ok(Key::known(&v).unwrap_or(Key::Other(v)))
229    }
230
231    fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Key, E> {
232        match std::str::from_utf8(v) {
233            Ok(s) => self.visit_str(s),
234            Err(_) => Err(E::invalid_value(de::Unexpected::Bytes(v), &self)),
235        }
236    }
237}
238
239impl<'de> Deserialize<'de> for Key {
240    #[inline]
241    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Key, D::Error> {
242        d.deserialize_identifier(KeyVisitor)
243    }
244}
245
246/// Error on a repeated known field (matches the derive's behaviour).
247#[inline]
248fn once<E: de::Error>(seen: &mut u8, bit: u8, name: &'static str) -> Result<(), E> {
249    if *seen & bit != 0 {
250        return Err(E::duplicate_field(name));
251    }
252    *seen |= bit;
253    Ok(())
254}
255
256/// Scratch stacks shared by one deserialize call. Children and marks collect
257/// here, then move into exactly sized `Vec`s: serde's seq visitor grows by
258/// doubling (JSON gives no length), which left ~2x the needed capacity.
259#[derive(Default)]
260struct Scratch {
261    nodes: Vec<Node>,
262    marks: Vec<Mark>,
263}
264
265impl<'de> Deserialize<'de> for Node {
266    #[inline]
267    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Node, D::Error> {
268        NodeSeed(&mut Scratch::default()).deserialize(d)
269    }
270}
271
272struct NodeSeed<'a>(&'a mut Scratch);
273
274impl<'de> DeserializeSeed<'de> for NodeSeed<'_> {
275    type Value = Node;
276
277    #[inline]
278    fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Node, D::Error> {
279        d.deserialize_map(self)
280    }
281}
282
283impl<'de> Visitor<'de> for NodeSeed<'_> {
284    type Value = Node;
285
286    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
287        f.write_str("struct Node")
288    }
289
290    fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Node, A::Error> {
291        let mut n = Node::default();
292        let mut seen = 0u8;
293        while let Some(key) = map.next_key::<Key>()? {
294            match key {
295                Key::Type => {
296                    once(&mut seen, 1, "type")?;
297                    n.node_type = map.next_value()?;
298                }
299                Key::Attrs => {
300                    once(&mut seen, 2, "attrs")?;
301                    n.attrs = map.next_value()?;
302                }
303                Key::Content => {
304                    once(&mut seen, 4, "content")?;
305                    n.content = map.next_value_seed(OptVec::<Node>(self.0, PhantomData))?;
306                }
307                Key::Marks => {
308                    once(&mut seen, 8, "marks")?;
309                    n.marks = map.next_value_seed(OptVec::<Mark>(self.0, PhantomData))?;
310                }
311                Key::Text => {
312                    once(&mut seen, 16, "text")?;
313                    n.text = map.next_value()?;
314                }
315                Key::Other(k) => {
316                    let v: Value = map.next_value()?;
317                    n.extra_mut().insert(k, v);
318                }
319            }
320        }
321        Ok(n)
322    }
323}
324
325/// Element type collected through a [`Scratch`] stack.
326trait Stacked: Sized {
327    fn stack(s: &mut Scratch) -> &mut Vec<Self>;
328    fn next<'de, A: SeqAccess<'de>>(seq: &mut A, s: &mut Scratch)
329        -> Result<Option<Self>, A::Error>;
330}
331
332impl Stacked for Node {
333    #[inline]
334    fn stack(s: &mut Scratch) -> &mut Vec<Node> {
335        &mut s.nodes
336    }
337
338    #[inline]
339    fn next<'de, A: SeqAccess<'de>>(
340        seq: &mut A,
341        s: &mut Scratch,
342    ) -> Result<Option<Node>, A::Error> {
343        seq.next_element_seed(NodeSeed(s))
344    }
345}
346
347impl Stacked for Mark {
348    #[inline]
349    fn stack(s: &mut Scratch) -> &mut Vec<Mark> {
350        &mut s.marks
351    }
352
353    #[inline]
354    fn next<'de, A: SeqAccess<'de>>(
355        seq: &mut A,
356        _: &mut Scratch,
357    ) -> Result<Option<Mark>, A::Error> {
358        seq.next_element()
359    }
360}
361
362/// `Option<Vec<T>>` with the same `null`/error behaviour as serde's impls.
363struct OptVec<'a, T>(&'a mut Scratch, PhantomData<T>);
364
365impl<'de, T: Stacked> DeserializeSeed<'de> for OptVec<'_, T> {
366    type Value = Option<Vec<T>>;
367
368    #[inline]
369    fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
370        d.deserialize_option(self)
371    }
372}
373
374impl<'de, T: Stacked> Visitor<'de> for OptVec<'_, T> {
375    type Value = Option<Vec<T>>;
376
377    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
378        f.write_str("option")
379    }
380
381    #[inline]
382    fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
383        Ok(None)
384    }
385
386    #[inline]
387    fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
388        Ok(None)
389    }
390
391    #[inline]
392    fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
393        d.deserialize_seq(SeqVec(self.0, PhantomData)).map(Some)
394    }
395}
396
397/// Seq visitor: push onto the scratch stack, then one exact-capacity move.
398struct SeqVec<'a, T>(&'a mut Scratch, PhantomData<T>);
399
400impl<'de, T: Stacked> Visitor<'de> for SeqVec<'_, T> {
401    type Value = Vec<T>;
402
403    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
404        f.write_str("a sequence")
405    }
406
407    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Vec<T>, A::Error> {
408        let s = self.0;
409        let base = T::stack(s).len();
410        while let Some(x) = T::next(&mut seq, s)? {
411            T::stack(s).push(x);
412        }
413        let st = T::stack(s);
414        let mut v = Vec::with_capacity(st.len() - base);
415        v.extend(st.drain(base..));
416        Ok(v)
417    }
418}
419
420impl Serialize for Node {
421    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
422        let len = self.node_type.is_some() as usize
423            + self.attrs.is_some() as usize
424            + self.content.is_some() as usize
425            + self.marks.is_some() as usize
426            + self.text.is_some() as usize
427            + self.extra.as_ref().map_or(0, |e| e.len());
428        let mut m = s.serialize_map(Some(len))?;
429        if let Some(t) = &self.node_type {
430            m.serialize_entry("type", t)?;
431        }
432        if let Some(a) = &self.attrs {
433            m.serialize_entry("attrs", a)?;
434        }
435        if let Some(c) = &self.content {
436            m.serialize_entry("content", c)?;
437        }
438        if let Some(mk) = &self.marks {
439            m.serialize_entry("marks", mk)?;
440        }
441        if let Some(t) = &self.text {
442            m.serialize_entry("text", t)?;
443        }
444        for (k, v) in self.extra.iter().flat_map(|e| e.iter()) {
445            m.serialize_entry(k, v)?;
446        }
447        m.end()
448    }
449}
450
451impl<'de> Deserialize<'de> for Mark {
452    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Mark, D::Error> {
453        struct V;
454        impl<'de> Visitor<'de> for V {
455            type Value = Mark;
456
457            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
458                f.write_str("struct Mark")
459            }
460
461            fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Mark, A::Error> {
462                let mut mark_type: Option<String> = None;
463                let mut attrs = None;
464                let mut extra: Option<Box<Map<String, Value>>> = None;
465                let mut seen = 0u8;
466                while let Some(key) = map.next_key::<Key>()? {
467                    match key {
468                        Key::Type => {
469                            once(&mut seen, 1, "type")?;
470                            mark_type = Some(map.next_value()?);
471                        }
472                        Key::Attrs => {
473                            once(&mut seen, 2, "attrs")?;
474                            attrs = map.next_value()?;
475                        }
476                        Key::Content => extra_entry(&mut map, &mut extra, "content")?,
477                        Key::Marks => extra_entry(&mut map, &mut extra, "marks")?,
478                        Key::Text => extra_entry(&mut map, &mut extra, "text")?,
479                        Key::Other(k) => {
480                            let v: Value = map.next_value()?;
481                            extra.get_or_insert_with(Default::default).insert(k, v);
482                        }
483                    }
484                }
485                let mark_type = mark_type.ok_or_else(|| de::Error::missing_field("type"))?;
486                Ok(Mark {
487                    mark_type,
488                    attrs,
489                    extra,
490                })
491            }
492        }
493        d.deserialize_map(V)
494    }
495}
496
497/// `Mark` has no `content`/`marks`/`text` fields: those keys are unknown there.
498#[inline]
499fn extra_entry<'de, A: MapAccess<'de>>(
500    map: &mut A,
501    extra: &mut Option<Box<Map<String, Value>>>,
502    key: &str,
503) -> Result<(), A::Error> {
504    let v: Value = map.next_value()?;
505    extra
506        .get_or_insert_with(Default::default)
507        .insert(key.to_owned(), v);
508    Ok(())
509}
510
511impl Serialize for Mark {
512    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
513        let len = 1 + self.attrs.is_some() as usize + self.extra.as_ref().map_or(0, |e| e.len());
514        let mut m = s.serialize_map(Some(len))?;
515        m.serialize_entry("type", &self.mark_type)?;
516        if let Some(a) = &self.attrs {
517            m.serialize_entry("attrs", a)?;
518        }
519        for (k, v) in self.extra.iter().flat_map(|e| e.iter()) {
520            m.serialize_entry(k, v)?;
521        }
522        m.end()
523    }
524}