Skip to main content

jsonld_core/object/
list.rs

1use super::{Any, InvalidExpandedJson, MappedEq};
2use crate::{HashMap, Id, IndexedObject, Relabel, TryFromJson, ValidId};
3use contextual::WithContext;
4use derive_where::derive_where;
5use jsonld_syntax::{IntoJson, IntoJsonWithContext};
6use rdfx::{
7    LocalGenerator,
8    vocabulary::{Vocabulary, VocabularyMut},
9};
10use std::hash::Hash;
11
12#[allow(clippy::derived_hash_with_manual_eq)]
13#[derive(Debug, Clone, Hash)]
14#[derive_where(PartialEq; T: Eq + Hash, B: Eq + Hash)]
15/// List object.
16pub struct List<T, B> {
17    entry: Vec<IndexedObject<T, B>>,
18}
19
20impl<T: Eq + Hash, B: Eq + Hash> Eq for List<T, B> {}
21
22impl<T, B> List<T, B> {
23    /// Creates a new list object.
24    #[must_use]
25    pub fn new(objects: Vec<IndexedObject<T, B>>) -> Self {
26        Self { entry: objects }
27    }
28
29    /// Removes every object of the list and returns them, in order.
30    pub(crate) fn take_entries(&mut self) -> Vec<IndexedObject<T, B>> {
31        std::mem::take(&mut self.entry)
32    }
33
34    /// Returns the number of objects in the list.
35    #[must_use]
36    pub fn len(&self) -> usize {
37        self.entry.len()
38    }
39
40    /// Checks whether the list holds no objects.
41    #[must_use]
42    pub fn is_empty(&self) -> bool {
43        self.entry.is_empty()
44    }
45
46    /// Returns the objects of the `@list` entry, in list order.
47    ///
48    /// Alias for [`as_slice`](Self::as_slice).
49    #[must_use]
50    pub fn entry(&self) -> &[IndexedObject<T, B>] {
51        &self.entry
52    }
53
54    /// Mutably borrows the objects of the `@list` entry.
55    pub fn entry_mut(&mut self) -> &mut Vec<IndexedObject<T, B>> {
56        &mut self.entry
57    }
58
59    /// Returns the objects of the list as a slice, in list order.
60    #[must_use]
61    pub fn as_slice(&self) -> &[IndexedObject<T, B>] {
62        self.entry.as_slice()
63    }
64
65    /// Returns the objects of the list as a mutable slice, in list order.
66    pub fn as_mut_slice(&mut self) -> &mut [IndexedObject<T, B>] {
67        self.entry.as_mut_slice()
68    }
69
70    /// Consumes the list, returning the objects of its `@list` entry.
71    #[must_use]
72    pub fn into_entry(mut self) -> Vec<IndexedObject<T, B>> {
73        self.take_entries()
74    }
75
76    /// Appends an object to the end of the list.
77    pub fn push(&mut self, object: IndexedObject<T, B>) {
78        self.entry.push(object);
79    }
80
81    /// Removes the last object of the list and returns it.
82    pub fn pop(&mut self) -> Option<IndexedObject<T, B>> {
83        self.entry.pop()
84    }
85
86    /// Returns an iterator over the objects of the list, in list order.
87    pub fn iter(&self) -> core::slice::Iter<'_, IndexedObject<T, B>> {
88        self.entry.iter()
89    }
90
91    /// Returns a mutable iterator over the objects of the list, in list
92    /// order.
93    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, IndexedObject<T, B>> {
94        self.entry.iter_mut()
95    }
96
97    /// Puts every literal of the list into canonical form, using the given
98    /// `buffer` to render numbers.
99    pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
100        for object in self {
101            object.canonicalize_with(buffer);
102        }
103    }
104
105    /// Puts every literal of the list into canonical form.
106    pub fn canonicalize(&mut self) {
107        let mut buffer = ryu_js::Buffer::new();
108        self.canonicalize_with(&mut buffer);
109    }
110
111    /// Rewrites every IRI and identifier of the list (recursively) with the
112    /// given functions.
113    pub fn map_ids<U, C>(self, mut map_iri: impl FnMut(T) -> U, mut map_id: impl FnMut(Id<T, B>) -> Id<U, C>) -> List<U, C>
114    where
115        U: Eq + Hash,
116        C: Eq + Hash,
117    {
118        self.map_ids_with(&mut map_iri, &mut map_id)
119    }
120
121    pub(crate) fn map_ids_with<U, C>(mut self, map_iri: &mut impl FnMut(T) -> U, map_id: &mut impl FnMut(Id<T, B>) -> Id<U, C>) -> List<U, C>
122    where
123        U: Eq + Hash,
124        C: Eq + Hash,
125    {
126        List::new(
127            self.take_entries()
128                .into_iter()
129                .map(|indexed_object| indexed_object.map_inner(|object| object.map_ids_with(map_iri, map_id)))
130                .collect(),
131        )
132    }
133}
134
135impl<T, B> Relabel<T, B> for List<T, B> {
136    fn relabel_with<N: VocabularyMut<Iri = T, BlankId = B>, G: LocalGenerator>(
137        &mut self,
138        vocabulary: &mut N,
139        generator: &mut G,
140        relabeling: &mut HashMap<B, ValidId<T, B>>,
141    ) -> Result<(), crate::id::GeneratedIdError>
142    where
143        T: Clone + Eq + Hash,
144        B: Clone + Eq + Hash,
145    {
146        for object in self {
147            object.relabel_with(vocabulary, generator, relabeling)?;
148        }
149        Ok(())
150    }
151}
152
153impl<T: Eq + Hash, B: Eq + Hash> List<T, B> {
154    pub(crate) fn try_from_json_object_in(
155        vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
156        object: jstrict::Object,
157        list_entry: jstrict::object::Entry,
158    ) -> Result<Self, InvalidExpandedJson> {
159        let list = Vec::try_from_json_in(vocabulary, list_entry.value)?;
160
161        match object.into_iter().next() {
162            Some(_) => Err(InvalidExpandedJson::UnexpectedEntry),
163            None => Ok(Self::new(list)),
164        }
165    }
166}
167
168impl<T, B> Any<T, B> for List<T, B> {
169    fn as_ref(&self) -> super::Ref<'_, T, B> {
170        super::Ref::List(self)
171    }
172}
173
174impl<T: Eq + Hash, B: Eq + Hash> MappedEq for List<T, B> {
175    type BlankId = B;
176
177    fn mapped_eq<'a, 'b, F: Clone + Fn(&'a B) -> &'b B>(&'a self, other: &Self, f: F) -> bool
178    where
179        B: 'a + 'b,
180    {
181        self.entry.mapped_eq(&other.entry, f)
182    }
183}
184
185impl<'a, T, B> IntoIterator for &'a List<T, B> {
186    type Item = &'a IndexedObject<T, B>;
187    type IntoIter = core::slice::Iter<'a, IndexedObject<T, B>>;
188
189    fn into_iter(self) -> Self::IntoIter {
190        self.iter()
191    }
192}
193
194impl<'a, T, B> IntoIterator for &'a mut List<T, B> {
195    type Item = &'a mut IndexedObject<T, B>;
196    type IntoIter = core::slice::IterMut<'a, IndexedObject<T, B>>;
197
198    fn into_iter(self) -> Self::IntoIter {
199        self.iter_mut()
200    }
201}
202
203impl<T, B> IntoIterator for List<T, B> {
204    type Item = IndexedObject<T, B>;
205    type IntoIter = std::vec::IntoIter<IndexedObject<T, B>>;
206
207    fn into_iter(mut self) -> Self::IntoIter {
208        self.take_entries().into_iter()
209    }
210}
211
212/// List object fragment.
213pub enum FragmentRef<'a, T, B> {
214    /// "@list" entry.
215    Entry(&'a [IndexedObject<T, B>]),
216}
217
218impl<'a, T, B> FragmentRef<'a, T, B> {
219    /// Returns the sub-fragments of this fragment: the objects of the list.
220    #[must_use]
221    pub fn sub_fragments(&self) -> SubFragments<'a, T, B> {
222        match self {
223            Self::Entry(e) => SubFragments(e.iter()),
224        }
225    }
226}
227
228/// Iterator over the sub-fragments of a list fragment.
229pub struct SubFragments<'a, T, B>(core::slice::Iter<'a, IndexedObject<T, B>>);
230
231impl<'a, T, B> Iterator for SubFragments<'a, T, B> {
232    type Item = super::FragmentRef<'a, T, B>;
233
234    fn next(&mut self) -> Option<Self::Item> {
235        self.0.next().map(super::FragmentRef::IndexedObject)
236    }
237}
238
239impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for List<T, B> {
240    fn into_json_with(mut self, vocabulary: &N) -> jstrict::Value {
241        let mut obj = jstrict::Object::new();
242
243        obj.insert("@list".into(), self.take_entries().into_with(vocabulary).into_json());
244
245        obj.into()
246    }
247}