Skip to main content

json_ld/core/
visit.rs

1use std::collections::HashMap;
2
3use btree_indexmap::{BTreeIndexMultiSet, BTreeIndexSet};
4use json_syntax::ryu_js;
5use rdf_syntax::{BlankIdBuf, Generator, Id};
6
7use crate::{
8	JsonLdLenient,
9	object::{JsonLdObjectMut, JsonLdObjectRef},
10};
11
12pub trait JsonLdVisit {
13	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef));
14
15	fn visit(&self, mut f: impl FnMut(JsonLdObjectRef)) {
16		self.visit_with(&mut f);
17	}
18
19	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut));
20
21	fn visit_mut(&mut self, mut f: impl FnMut(JsonLdObjectMut)) {
22		self.visit_mut_with(&mut f);
23	}
24
25	fn relabel_with(&mut self, relabeling: &mut JsonLdRelabeling<impl Generator>) {
26		self.visit_mut(|object| {
27			relabel_object(object, relabeling);
28		})
29	}
30
31	fn relabel<G: Generator>(&mut self, generator: G) -> JsonLdRelabeling<G> {
32		let mut relabeling = JsonLdRelabeling::new(generator);
33		self.relabel_with(&mut relabeling);
34		relabeling
35	}
36
37	fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
38		self.visit_mut(|object| {
39			canonicalize_object(object, buffer);
40		});
41	}
42
43	fn canonicalize(&mut self) {
44		let mut buffer = ryu_js::Buffer::new();
45		self.canonicalize_with(&mut buffer);
46	}
47
48	fn relabel_and_canonicalize_with(
49		&mut self,
50		relabeling: &mut JsonLdRelabeling<impl Generator>,
51		buffer: &mut ryu_js::Buffer,
52	) {
53		self.visit_mut(|mut object| {
54			relabel_object(object.reborrow(), relabeling);
55			canonicalize_object(object, buffer);
56		});
57	}
58
59	fn relabel_and_canonicalize<G: Generator>(&mut self, generator: G) -> JsonLdRelabeling<G> {
60		let mut relabeling = JsonLdRelabeling::new(generator);
61		let mut buffer = ryu_js::Buffer::new();
62		self.relabel_and_canonicalize_with(&mut relabeling, &mut buffer);
63		relabeling
64	}
65}
66
67fn relabel_object(object: JsonLdObjectMut, relabeling: &mut JsonLdRelabeling<impl Generator>) {
68	if let JsonLdObjectMut::Node(node) = object {
69		node.id = Some(relabeling.relabel(node.id.take()));
70
71		if let Some(types) = node.types.take() {
72			node.types = Some(
73				types
74					.into_iter()
75					.map(|ty| relabeling.relabel(Some(ty)))
76					.collect(),
77			)
78		}
79	}
80}
81
82fn canonicalize_object(object: JsonLdObjectMut, buffer: &mut ryu_js::Buffer) {
83	if let JsonLdObjectMut::Value(value) = object {
84		value.canonicalize_with(buffer);
85	}
86}
87
88impl<T> JsonLdVisit for [T]
89where
90	T: JsonLdVisit,
91{
92	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
93		for t in self {
94			t.visit_with(f);
95		}
96	}
97
98	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
99		for t in self {
100			t.visit_mut_with(f);
101		}
102	}
103}
104
105impl<T> JsonLdVisit for BTreeIndexSet<T>
106where
107	T: JsonLdVisit + Ord,
108{
109	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
110		for t in self {
111			t.visit_with(f);
112		}
113	}
114
115	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
116		for mut t in std::mem::take(self) {
117			t.visit_mut_with(f);
118			self.insert(t);
119		}
120	}
121}
122
123impl<T> JsonLdVisit for BTreeIndexMultiSet<T>
124where
125	T: JsonLdVisit + Ord,
126{
127	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
128		for t in self {
129			t.visit_with(f);
130		}
131	}
132
133	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
134		for mut t in std::mem::take(self) {
135			t.visit_mut_with(f);
136			self.insert(t);
137		}
138	}
139}
140
141impl<T> JsonLdVisit for Option<T>
142where
143	T: JsonLdVisit,
144{
145	fn visit_with(&self, f: &mut impl FnMut(JsonLdObjectRef)) {
146		if let Some(t) = self {
147			t.visit_with(f);
148		}
149	}
150
151	fn visit_mut_with(&mut self, f: &mut impl FnMut(JsonLdObjectMut)) {
152		if let Some(t) = self {
153			t.visit_mut_with(f);
154		}
155	}
156}
157
158pub struct JsonLdRelabeling<G> {
159	generator: G,
160	map: HashMap<BlankIdBuf, Id>,
161}
162
163impl<G> JsonLdRelabeling<G> {
164	pub fn new(generator: G) -> Self {
165		Self {
166			generator,
167			map: HashMap::new(),
168		}
169	}
170}
171
172impl<G> JsonLdRelabeling<G>
173where
174	G: Generator,
175{
176	pub fn relabel(&mut self, id: Option<JsonLdLenient<Id>>) -> JsonLdLenient<Id> {
177		match id {
178			Some(JsonLdLenient::Valid(Id::BlankId(b))) => JsonLdLenient::Valid(
179				self.map
180					.entry(b)
181					.or_insert_with(|| self.generator.next_id())
182					.clone(),
183			),
184			Some(id) => id,
185			None => JsonLdLenient::Valid(self.generator.next_id()),
186		}
187	}
188}