1use super::{Any, InvalidExpandedJson, MappedEq};
2use crate::{Id, IndexedObject, Relabel, TryFromJson};
3use contextual::WithContext;
4use educe::Educe;
5use json_ld_syntax::{IntoJson, IntoJsonWithContext};
6use rdf_types::{Generator, Subject, Vocabulary, VocabularyMut};
7use std::hash::Hash;
8
9#[allow(clippy::derived_hash_with_manual_eq)]
10#[derive(Educe, Debug, Clone, Hash)]
11#[educe(
12 PartialEq(bound = "T: Eq + Hash, B: Eq + Hash"),
13 Eq(bound = "T: Eq + Hash, B: Eq + Hash")
14)]
15pub struct List<T, B> {
17 entry: Vec<IndexedObject<T, B>>,
18}
19
20impl<T, B> List<T, B> {
21 pub fn new(objects: Vec<IndexedObject<T, B>>) -> Self {
23 Self { entry: objects }
24 }
25
26 pub fn len(&self) -> usize {
27 self.entry.len()
28 }
29
30 pub fn is_empty(&self) -> bool {
31 self.entry.is_empty()
32 }
33
34 pub fn entry(&self) -> &[IndexedObject<T, B>] {
38 &self.entry
39 }
40
41 pub fn entry_mut(&mut self) -> &mut Vec<IndexedObject<T, B>> {
42 &mut self.entry
43 }
44
45 pub fn as_slice(&self) -> &[IndexedObject<T, B>] {
46 self.entry.as_slice()
47 }
48
49 pub fn as_mut_slice(&mut self) -> &mut [IndexedObject<T, B>] {
50 self.entry.as_mut_slice()
51 }
52
53 pub fn into_entry(self) -> Vec<IndexedObject<T, B>> {
54 self.entry
55 }
56
57 pub fn push(&mut self, object: IndexedObject<T, B>) {
58 self.entry.push(object)
59 }
60
61 pub fn pop(&mut self) -> Option<IndexedObject<T, B>> {
62 self.entry.pop()
63 }
64
65 pub fn iter(&self) -> core::slice::Iter<IndexedObject<T, B>> {
66 self.entry.iter()
67 }
68
69 pub fn iter_mut(&mut self) -> core::slice::IterMut<IndexedObject<T, B>> {
70 self.entry.iter_mut()
71 }
72
73 pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
78 for object in self {
79 object.canonicalize_with(buffer)
80 }
81 }
82
83 pub fn canonicalize(&mut self) {
85 let mut buffer = ryu_js::Buffer::new();
86 self.canonicalize_with(&mut buffer)
87 }
88
89 pub fn map_ids<U, C>(
91 self,
92 mut map_iri: impl FnMut(T) -> U,
93 mut map_id: impl FnMut(Id<T, B>) -> Id<U, C>,
94 ) -> List<U, C>
95 where
96 U: Eq + Hash,
97 C: Eq + Hash,
98 {
99 self.map_ids_with(&mut map_iri, &mut map_id)
100 }
101
102 pub(crate) fn map_ids_with<U, C>(
103 self,
104 map_iri: &mut impl FnMut(T) -> U,
105 map_id: &mut impl FnMut(Id<T, B>) -> Id<U, C>,
106 ) -> List<U, C>
107 where
108 U: Eq + Hash,
109 C: Eq + Hash,
110 {
111 List::new(
112 self.entry
113 .into_iter()
114 .map(|indexed_object| {
115 indexed_object.map_inner(|object| object.map_ids_with(map_iri, map_id))
116 })
117 .collect(),
118 )
119 }
120}
121
122impl<T, B> Relabel<T, B> for List<T, B> {
123 fn relabel_with<N: Vocabulary<Iri = T, BlankId = B>, G: Generator<N>>(
124 &mut self,
125 vocabulary: &mut N,
126 generator: &mut G,
127 relabeling: &mut hashbrown::HashMap<B, Subject<T, B>>,
128 ) where
129 T: Clone + Eq + Hash,
130 B: Clone + Eq + Hash,
131 {
132 for object in self {
133 object.relabel_with(vocabulary, generator, relabeling)
134 }
135 }
136}
137
138impl<T: Eq + Hash, B: Eq + Hash> List<T, B> {
139 pub(crate) fn try_from_json_object_in(
140 vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
141 object: json_syntax::Object,
142 list_entry: json_syntax::object::Entry,
143 ) -> Result<Self, InvalidExpandedJson> {
144 let list = Vec::try_from_json_in(vocabulary, list_entry.value)?;
145
146 match object.into_iter().next() {
147 Some(_) => Err(InvalidExpandedJson::UnexpectedEntry),
148 None => Ok(Self::new(list)),
149 }
150 }
151}
152
153impl<T, B> Any<T, B> for List<T, B> {
154 fn as_ref(&self) -> super::Ref<T, B> {
155 super::Ref::List(self)
156 }
157}
158
159impl<T: Eq + Hash, B: Eq + Hash> MappedEq for List<T, B> {
160 type BlankId = B;
161
162 fn mapped_eq<'a, 'b, F: Clone + Fn(&'a B) -> &'b B>(&'a self, other: &Self, f: F) -> bool
163 where
164 B: 'a + 'b,
165 {
166 self.entry.mapped_eq(&other.entry, f)
167 }
168}
169
170impl<'a, T, B> IntoIterator for &'a List<T, B> {
171 type Item = &'a IndexedObject<T, B>;
172 type IntoIter = core::slice::Iter<'a, IndexedObject<T, B>>;
173
174 fn into_iter(self) -> Self::IntoIter {
175 self.iter()
176 }
177}
178
179impl<'a, T, B> IntoIterator for &'a mut List<T, B> {
180 type Item = &'a mut IndexedObject<T, B>;
181 type IntoIter = core::slice::IterMut<'a, IndexedObject<T, B>>;
182
183 fn into_iter(self) -> Self::IntoIter {
184 self.iter_mut()
185 }
186}
187
188impl<T, B> IntoIterator for List<T, B> {
189 type Item = IndexedObject<T, B>;
190 type IntoIter = std::vec::IntoIter<IndexedObject<T, B>>;
191
192 fn into_iter(self) -> Self::IntoIter {
193 self.entry.into_iter()
194 }
195}
196
197pub enum FragmentRef<'a, T, B> {
199 Entry(&'a [IndexedObject<T, B>]),
201
202 Key,
204
205 Value(&'a [IndexedObject<T, B>]),
207}
208
209impl<T, B, N: Vocabulary<Iri = T, BlankId = B>> IntoJsonWithContext<N> for List<T, B> {
210 fn into_json_with(self, vocabulary: &N) -> json_syntax::Value {
211 let mut obj = json_syntax::Object::new();
212
213 obj.insert("@list".into(), self.entry.into_with(vocabulary).into_json());
214
215 obj.into()
216 }
217}