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)]
15pub 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 #[must_use]
25 pub fn new(objects: Vec<IndexedObject<T, B>>) -> Self {
26 Self { entry: objects }
27 }
28
29 pub(crate) fn take_entries(&mut self) -> Vec<IndexedObject<T, B>> {
31 std::mem::take(&mut self.entry)
32 }
33
34 #[must_use]
36 pub fn len(&self) -> usize {
37 self.entry.len()
38 }
39
40 #[must_use]
42 pub fn is_empty(&self) -> bool {
43 self.entry.is_empty()
44 }
45
46 #[must_use]
50 pub fn entry(&self) -> &[IndexedObject<T, B>] {
51 &self.entry
52 }
53
54 pub fn entry_mut(&mut self) -> &mut Vec<IndexedObject<T, B>> {
56 &mut self.entry
57 }
58
59 #[must_use]
61 pub fn as_slice(&self) -> &[IndexedObject<T, B>] {
62 self.entry.as_slice()
63 }
64
65 pub fn as_mut_slice(&mut self) -> &mut [IndexedObject<T, B>] {
67 self.entry.as_mut_slice()
68 }
69
70 #[must_use]
72 pub fn into_entry(mut self) -> Vec<IndexedObject<T, B>> {
73 self.take_entries()
74 }
75
76 pub fn push(&mut self, object: IndexedObject<T, B>) {
78 self.entry.push(object);
79 }
80
81 pub fn pop(&mut self) -> Option<IndexedObject<T, B>> {
83 self.entry.pop()
84 }
85
86 pub fn iter(&self) -> core::slice::Iter<'_, IndexedObject<T, B>> {
88 self.entry.iter()
89 }
90
91 pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, IndexedObject<T, B>> {
94 self.entry.iter_mut()
95 }
96
97 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 pub fn canonicalize(&mut self) {
107 let mut buffer = ryu_js::Buffer::new();
108 self.canonicalize_with(&mut buffer);
109 }
110
111 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
212pub enum FragmentRef<'a, T, B> {
214 Entry(&'a [IndexedObject<T, B>]),
216}
217
218impl<'a, T, B> FragmentRef<'a, T, B> {
219 #[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
228pub 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}