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