json_ld_core/
indexed.rs

1use crate::object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject};
2use json_ld_syntax::{IntoJson, IntoJsonWithContext};
3use rdf_types::VocabularyMut;
4use std::convert::{TryFrom, TryInto};
5use std::ops::{Deref, DerefMut};
6
7/// Indexed objects.
8///
9/// Nodes and value objects may be indexed by a string in JSON-LD.
10/// This type is a wrapper around any kind of indexable data.
11///
12/// It is a pointer type that `Deref` into the underlying value.
13#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
14pub struct Indexed<T> {
15	/// Index.
16	index: Option<String>,
17
18	/// Value.
19	value: T,
20}
21
22impl<T> Indexed<T> {
23	/// Creates a non-indexed value, without metadata.
24	pub fn none(value: T) -> Self {
25		Self::new(value, None)
26	}
27
28	/// Create a new (maybe) indexed value.
29	#[inline(always)]
30	pub fn new(value: T, index: Option<String>) -> Self {
31		Indexed { value, index }
32	}
33
34	/// Get a reference to the inner value.
35	#[inline(always)]
36	pub fn inner(&self) -> &T {
37		&self.value
38	}
39
40	pub fn inner_mut(&mut self) -> &mut T {
41		&mut self.value
42	}
43
44	/// Drop the index and return the underlying value.
45	#[inline(always)]
46	pub fn into_inner(self) -> T {
47		self.value
48	}
49
50	/// Get the index, if any.
51	#[inline(always)]
52	pub fn index(&self) -> Option<&str> {
53		match &self.index {
54			Some(index) => Some(index.as_str()),
55			None => None,
56		}
57	}
58
59	/// Set the value index.
60	#[inline(always)]
61	pub fn set_index(&mut self, index: Option<String>) {
62		self.index = index
63	}
64
65	/// Turn this indexed value into its components: inner value and index.
66	#[inline(always)]
67	pub fn into_parts(self) -> (T, Option<String>) {
68		(self.value, self.index)
69	}
70
71	/// Cast the inner value.
72	#[inline(always)]
73	pub fn map_inner<U, F>(self, f: F) -> Indexed<U>
74	where
75		F: FnOnce(T) -> U,
76	{
77		Indexed::new(f(self.value), self.index)
78	}
79
80	/// Cast the inner value.
81	#[inline(always)]
82	pub fn cast<U: From<T>>(self) -> Indexed<U> {
83		Indexed::new(self.value.into(), self.index)
84	}
85
86	/// Try to cast the inner value.
87	#[inline(always)]
88	pub fn try_cast<U: TryFrom<T>>(self) -> Result<Indexed<U>, Indexed<U::Error>> {
89		match self.value.try_into() {
90			Ok(value) => Ok(Indexed::new(value, self.index)),
91			Err(e) => Err(Indexed::new(e, self.index)),
92		}
93	}
94}
95
96impl<T, B, O: TryFromJsonObject<T, B>> TryFromJson<T, B> for Indexed<O> {
97	fn try_from_json_in(
98		vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
99		value: json_syntax::Value,
100	) -> Result<Self, InvalidExpandedJson> {
101		match value {
102			json_syntax::Value::Object(object) => Self::try_from_json_object_in(vocabulary, object),
103			_ => Err(InvalidExpandedJson::InvalidObject),
104		}
105	}
106}
107
108impl<T, B, O: TryFromJsonObject<T, B>> TryFromJsonObject<T, B> for Indexed<O> {
109	fn try_from_json_object_in(
110		vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>,
111		mut object: json_syntax::Object,
112	) -> Result<Self, InvalidExpandedJson> {
113		let index = match object
114			.remove_unique("@index")
115			.map_err(InvalidExpandedJson::duplicate_key)?
116		{
117			Some(index_entry) => match index_entry.value {
118				json_syntax::Value::String(index) => Some(index.to_string()),
119				_ => return Err(InvalidExpandedJson::InvalidIndex),
120			},
121			None => None,
122		};
123
124		let value = O::try_from_json_object_in(vocabulary, object)?;
125		Ok(Self::new(value, index))
126	}
127}
128
129impl<T> From<T> for Indexed<T> {
130	#[inline(always)]
131	fn from(value: T) -> Indexed<T> {
132		Indexed::new(value, None)
133	}
134}
135
136impl<T> Deref for Indexed<T> {
137	type Target = T;
138
139	#[inline(always)]
140	fn deref(&self) -> &T {
141		&self.value
142	}
143}
144
145impl<T> DerefMut for Indexed<T> {
146	#[inline(always)]
147	fn deref_mut(&mut self) -> &mut T {
148		&mut self.value
149	}
150}
151
152impl<T> AsRef<T> for Indexed<T> {
153	#[inline(always)]
154	fn as_ref(&self) -> &T {
155		&self.value
156	}
157}
158
159impl<T> AsMut<T> for Indexed<T> {
160	#[inline(always)]
161	fn as_mut(&mut self) -> &mut T {
162		&mut self.value
163	}
164}
165
166impl<T: IntoJsonWithContext<N>, N> IntoJsonWithContext<N> for Indexed<T> {
167	fn into_json_with(self, vocabulary: &N) -> json_syntax::Value {
168		let mut result = self.value.into_json_with(vocabulary);
169
170		if let Some(obj) = result.as_object_mut() {
171			if let Some(index) = self.index {
172				obj.insert("@index".into(), index.into_json());
173			}
174		}
175
176		result
177	}
178}
179
180// impl<J: JsonClone, K: JsonFrom<J>, T: AsJson<J, K>> AsJson<J, K> for Indexed<T> {
181// 	fn as_json_with(
182// 		&self,
183// 		meta: impl Clone + Fn(Option<&J::MetaData>) -> <K as Json>::MetaData,
184// 	) -> K {
185// 		let mut json = self.value.as_json_with(meta.clone());
186
187// 		if let Some(obj) = json.as_object_mut() {
188// 			if let Some(index) = &self.index {
189// 				obj.insert(
190// 					K::new_key(Keyword::Index.into_str(), meta(None)),
191// 					index.as_json_with(meta(None)),
192// 				);
193// 			}
194// 		}
195
196// 		json
197// 	}
198// }