nondestructive/yaml/
data.rs

1use core::fmt;
2use core::hash::Hash;
3use core::mem;
4use core::num::NonZeroUsize;
5
6use alloc::boxed::Box;
7
8use std::collections::hash_map::{self, HashMap};
9
10use bstr::BStr;
11#[cfg(feature = "serde-edits")]
12use serde::{Deserialize, Serialize};
13use twox_hash::xxh3::{Hash128, HasherExt};
14
15use crate::yaml::raw;
16
17/// The unique hash of a string.
18#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19#[cfg_attr(feature = "serde-edits", derive(Serialize, Deserialize))]
20#[cfg_attr(feature = "serde-edits", serde(transparent))]
21#[repr(transparent)]
22pub(crate) struct StringId([u8; 16]);
23
24impl fmt::Display for StringId {
25    #[inline]
26    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27        write!(f, "{}", Hex(&self.0))
28    }
29}
30
31impl fmt::Debug for StringId {
32    #[inline]
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        f.debug_tuple("StringId").field(&Hex(&self.0)).finish()
35    }
36}
37
38struct Hex<'a>(&'a [u8]);
39
40impl fmt::Display for Hex<'_> {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        for byte in self.0 {
43            write!(f, "{byte:02x}")?;
44        }
45
46        Ok(())
47    }
48}
49
50impl fmt::Debug for Hex<'_> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        fmt::Display::fmt(self, f)
53    }
54}
55
56/// An opaque identifier for a value inside of a [`Document`].
57///
58/// Is constructed through [`Value::id`], [`Mapping::id`], or [`Sequence::id`] and can
59/// be converted into a [`Value`] again through [`Document::value`] or
60/// [`Document::value_mut`].
61///
62/// [`Value::id`]: crate::yaml::Value::id
63/// [`Mapping::id`]: crate::yaml::Mapping::id
64/// [`Sequence::id`]: crate::yaml::Sequence::id
65/// [`Value`]: crate::yaml::Value
66/// [`Document`]: crate::yaml::Document
67/// [`Document::value`]: crate::yaml::Document::value
68/// [`Document::value_mut`]: crate::yaml::Document::value_mut
69#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
70#[cfg_attr(feature = "serde-edits", derive(Serialize, Deserialize))]
71#[cfg_attr(feature = "serde-edits", serde(transparent))]
72#[repr(transparent)]
73pub struct Id(NonZeroUsize);
74
75impl Id {
76    #[inline]
77    fn get(self) -> usize {
78        self.0.get().wrapping_sub(1)
79    }
80}
81
82impl fmt::Display for Id {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        write!(f, "{:08x}", self.get())
85    }
86}
87
88#[derive(Debug, Clone)]
89#[cfg_attr(feature = "serde-edits", derive(Serialize, Deserialize))]
90pub(crate) struct Entry {
91    raw: raw::Raw,
92    layout: raw::Layout,
93}
94
95/// Strings cache.
96#[derive(Clone, Default)]
97#[cfg_attr(feature = "serde-edits", derive(Serialize, Deserialize))]
98pub(crate) struct Data {
99    strings: HashMap<StringId, Box<[u8]>>,
100    slab: slab::Slab<Entry>,
101}
102
103impl Data {
104    /// Get a string.
105    #[inline]
106    #[must_use]
107    pub(crate) fn str(&self, id: StringId) -> &BStr {
108        let Some(string) = self.strings.get(&id) else {
109            panic!("missing string with id {id}");
110        };
111
112        BStr::new(string.as_ref())
113    }
114
115    /// Insert a string into the string cache.
116    pub(crate) fn insert_str<B>(&mut self, string: B) -> StringId
117    where
118        B: AsRef<[u8]>,
119    {
120        let mut hasher = Hash128::default();
121        string.as_ref().hash(&mut hasher);
122        let hash = hasher.finish_ext();
123        let hash = hash.to_le_bytes();
124        let id = StringId(hash);
125
126        if let hash_map::Entry::Vacant(e) = self.strings.entry(id) {
127            e.insert(string.as_ref().into());
128        }
129
130        id
131    }
132
133    #[inline]
134    pub(crate) fn layout(&self, id: Id) -> &raw::Layout {
135        if let Some(raw) = self.slab.get(id.get()) {
136            return &raw.layout;
137        }
138
139        panic!("expected layout at {id}")
140    }
141
142    #[inline]
143    pub(crate) fn prefix(&self, id: Id) -> &BStr {
144        self.str(self.layout(id).prefix)
145    }
146
147    #[inline]
148    pub(crate) fn pair(&self, id: Id) -> (&raw::Raw, &raw::Layout) {
149        if let Some(raw) = self.slab.get(id.get()) {
150            return (&raw.raw, &raw.layout);
151        }
152
153        panic!("expected raw at {id}")
154    }
155
156    #[inline]
157    pub(crate) fn raw(&self, id: Id) -> &raw::Raw {
158        if let Some(raw) = self.slab.get(id.get()) {
159            return &raw.raw;
160        }
161
162        panic!("expected raw at {id}")
163    }
164
165    #[inline]
166    pub(crate) fn raw_mut(&mut self, id: Id) -> &mut raw::Raw {
167        if let Some(raw) = self.slab.get_mut(id.get()) {
168            return &mut raw.raw;
169        }
170
171        panic!("expected raw at {id}")
172    }
173
174    #[inline]
175    pub(crate) fn sequence(&self, id: Id) -> &raw::Sequence {
176        if let Some(Entry {
177            raw: raw::Raw::Sequence(raw),
178            ..
179        }) = self.slab.get(id.get())
180        {
181            return raw;
182        }
183
184        panic!("expected sequence at {id}")
185    }
186
187    #[inline]
188    pub(crate) fn sequence_mut(&mut self, id: Id) -> &mut raw::Sequence {
189        if let Some(Entry {
190            raw: raw::Raw::Sequence(raw),
191            ..
192        }) = self.slab.get_mut(id.get())
193        {
194            return raw;
195        }
196
197        panic!("expected sequence at {id}")
198    }
199
200    #[inline]
201    pub(crate) fn mapping(&self, id: Id) -> &raw::Mapping {
202        if let Some(Entry {
203            raw: raw::Raw::Mapping(raw),
204            ..
205        }) = self.slab.get(id.get())
206        {
207            return raw;
208        }
209
210        panic!("expected mapping at {id}")
211    }
212
213    #[inline]
214    pub(crate) fn sequence_item(&self, id: Id) -> &raw::SequenceItem {
215        if let Some(Entry {
216            raw: raw::Raw::SequenceItem(raw),
217            ..
218        }) = self.slab.get(id.get())
219        {
220            return raw;
221        }
222
223        panic!("expected sequence item at {id}")
224    }
225
226    #[inline]
227    pub(crate) fn mapping_item(&self, id: Id) -> &raw::MappingItem {
228        if let Some(Entry {
229            raw: raw::Raw::MappingItem(raw),
230            ..
231        }) = self.slab.get(id.get())
232        {
233            return raw;
234        }
235
236        panic!("expected mapping item at {id}")
237    }
238
239    #[inline]
240    pub(crate) fn mapping_mut(&mut self, id: Id) -> &mut raw::Mapping {
241        if let Some(Entry {
242            raw: raw::Raw::Mapping(raw),
243            ..
244        }) = self.slab.get_mut(id.get())
245        {
246            return raw;
247        }
248
249        panic!("expected mapping at {id}")
250    }
251
252    /// Insert a raw value and return its identifier.
253    #[inline]
254    pub(crate) fn insert(&mut self, raw: raw::Raw, prefix: StringId, parent: Option<Id>) -> Id {
255        let index = self.slab.insert(Entry {
256            raw,
257            layout: raw::Layout { prefix, parent },
258        });
259        let index = NonZeroUsize::new(index.wrapping_add(1)).expect("ran out of ids");
260        Id(index)
261    }
262
263    /// Drop a value recursively.
264    #[inline]
265    pub(crate) fn drop(&mut self, id: Id) {
266        let Some(value) = self.slab.try_remove(id.get()) else {
267            return;
268        };
269
270        self.drop_kind(value.raw);
271    }
272
273    /// Drop a raw value recursively.
274    #[inline]
275    pub(crate) fn drop_kind(&mut self, raw: raw::Raw) {
276        match raw {
277            raw::Raw::Mapping(raw) => {
278                for item in raw.items {
279                    self.drop(item);
280                }
281            }
282            raw::Raw::MappingItem(raw) => {
283                let item = self.slab.remove(raw.value.get());
284                self.drop_kind(item.raw);
285            }
286            raw::Raw::Sequence(raw) => {
287                for item in raw.items {
288                    self.drop(item);
289                }
290            }
291            raw::Raw::SequenceItem(raw) => {
292                let item = self.slab.remove(raw.value.get());
293                self.drop_kind(item.raw);
294            }
295            _ => {}
296        }
297    }
298
299    /// Replace a raw value.
300    pub(crate) fn replace<T>(&mut self, id: Id, raw: T)
301    where
302        T: Into<raw::Raw>,
303    {
304        let Some(value) = self.slab.get_mut(id.get()) else {
305            return;
306        };
307
308        let removed = mem::replace(&mut value.raw, raw.into());
309        self.drop_kind(removed);
310    }
311
312    /// Replace with indentation.
313    pub(crate) fn replace_with(&mut self, id: Id, prefix: StringId, raw: raw::Raw) {
314        let Some(value) = self.slab.get_mut(id.get()) else {
315            return;
316        };
317
318        value.layout.prefix = prefix;
319        let removed = mem::replace(&mut value.raw, raw);
320        self.drop_kind(removed);
321    }
322}