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 #[must_use]
31 pub fn len(&self) -> usize {
32 self.entry.len()
33 }
34
35 #[must_use]
37 pub fn is_empty(&self) -> bool {
38 self.entry.is_empty()
39 }
40
41 #[must_use]
45 pub fn entry(&self) -> &[IndexedObject<T, B>] {
46 &self.entry
47 }
48
49 pub fn entry_mut(&mut self) -> &mut Vec<IndexedObject<T, B>> {
51 &mut self.entry
52 }
53
54 #[must_use]
56 pub fn as_slice(&self) -> &[IndexedObject<T, B>] {
57 self.entry.as_slice()
58 }
59
60 pub fn as_mut_slice(&mut self) -> &mut [IndexedObject<T, B>] {
62 self.entry.as_mut_slice()
63 }
64
65 #[must_use]
67 pub fn into_entry(self) -> Vec<IndexedObject<T, B>> {
68 self.entry
69 }
70
71 pub fn push(&mut self, object: IndexedObject<T, B>) {
73 self.entry.push(object);
74 }
75
76 pub fn pop(&mut self) -> Option<IndexedObject<T, B>> {
78 self.entry.pop()
79 }
80
81 pub fn iter(&self) -> core::slice::Iter<'_, IndexedObject<T, B>> {
83 self.entry.iter()
84 }
85
86 pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, IndexedObject<T, B>> {
89 self.entry.iter_mut()
90 }
91
92 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 pub fn canonicalize(&mut self) {
102 let mut buffer = ryu_js::Buffer::new();
103 self.canonicalize_with(&mut buffer);
104 }
105
106 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
207pub enum FragmentRef<'a, T, B> {
209 Entry(&'a [IndexedObject<T, B>]),
211}
212
213impl<'a, T, B> FragmentRef<'a, T, B> {
214 #[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
223pub 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}