1use crate::object::{InvalidExpandedJson, TryFromJson, TryFromJsonObject};
2use jsonld_syntax::{IntoJson, IntoJsonWithContext, native_stack::on_sufficient_stack};
3use rdfx::vocabulary::VocabularyMut;
4use std::{
5 convert::{TryFrom, TryInto},
6 ops::{Deref, DerefMut},
7};
8
9#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
16pub struct Indexed<T> {
17 index: Option<String>,
19
20 value: T,
22}
23
24impl<T> Indexed<T> {
25 pub fn none(value: T) -> Self {
27 Self::new(value, None)
28 }
29
30 #[inline(always)]
32 pub fn new(value: T, index: Option<String>) -> Self {
33 Indexed { index, value }
34 }
35
36 #[inline(always)]
38 pub fn inner(&self) -> &T {
39 &self.value
40 }
41
42 pub fn inner_mut(&mut self) -> &mut T {
44 &mut self.value
45 }
46
47 #[inline(always)]
49 pub fn into_inner(self) -> T {
50 self.value
51 }
52
53 #[inline(always)]
55 pub fn index(&self) -> Option<&str> {
56 match &self.index {
57 Some(index) => Some(index.as_str()),
58 None => None,
59 }
60 }
61
62 #[inline(always)]
64 pub fn set_index(&mut self, index: Option<String>) {
65 self.index = index;
66 }
67
68 #[inline(always)]
71 pub fn into_parts(self) -> (T, Option<String>) {
72 (self.value, self.index)
73 }
74
75 #[inline(always)]
77 pub fn map_inner<U, F>(self, f: F) -> Indexed<U>
78 where
79 F: FnOnce(T) -> U,
80 {
81 Indexed::new(f(self.value), self.index)
82 }
83
84 #[inline(always)]
86 pub fn cast<U: From<T>>(self) -> Indexed<U> {
87 Indexed::new(self.value.into(), self.index)
88 }
89
90 #[inline(always)]
96 pub fn try_cast<U: TryFrom<T>>(self) -> Result<Indexed<U>, Indexed<U::Error>> {
97 match self.value.try_into() {
98 Ok(value) => Ok(Indexed::new(value, self.index)),
99 Err(e) => Err(Indexed::new(e, self.index)),
100 }
101 }
102}
103
104impl<T, B, O: TryFromJsonObject<T, B>> TryFromJson<T, B> for Indexed<O> {
105 fn try_from_json_in(vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>, value: jstrict::Value) -> Result<Self, InvalidExpandedJson> {
106 match value {
107 jstrict::Value::Object(object) => Self::try_from_json_object_in(vocabulary, object),
108 _ => Err(InvalidExpandedJson::InvalidObject),
109 }
110 }
111}
112
113impl<T, B, O: TryFromJsonObject<T, B>> TryFromJsonObject<T, B> for Indexed<O> {
119 fn try_from_json_object_in(vocabulary: &mut impl VocabularyMut<Iri = T, BlankId = B>, mut object: jstrict::Object) -> Result<Self, InvalidExpandedJson> {
120 on_sufficient_stack(move || {
121 let index = match object.remove_unique("@index").map_err(InvalidExpandedJson::duplicate_key)? {
122 Some(index_entry) => match index_entry.value {
123 jstrict::Value::String(index) => Some(index.to_string()),
124 _ => return Err(InvalidExpandedJson::InvalidIndex),
125 },
126 None => None,
127 };
128
129 let value = O::try_from_json_object_in(vocabulary, object)?;
130 Ok(Self::new(value, index))
131 })
132 }
133}
134
135impl<T> From<T> for Indexed<T> {
136 #[inline(always)]
137 fn from(value: T) -> Indexed<T> {
138 Indexed::new(value, None)
139 }
140}
141
142impl<T> Deref for Indexed<T> {
143 type Target = T;
144
145 #[inline(always)]
146 fn deref(&self) -> &T {
147 &self.value
148 }
149}
150
151impl<T> DerefMut for Indexed<T> {
152 #[inline(always)]
153 fn deref_mut(&mut self) -> &mut T {
154 &mut self.value
155 }
156}
157
158impl<T> AsRef<T> for Indexed<T> {
159 #[inline(always)]
160 fn as_ref(&self) -> &T {
161 &self.value
162 }
163}
164
165impl<T> AsMut<T> for Indexed<T> {
166 #[inline(always)]
167 fn as_mut(&mut self) -> &mut T {
168 &mut self.value
169 }
170}
171
172impl<T: IntoJsonWithContext<N>, N> IntoJsonWithContext<N> for Indexed<T> {
175 fn into_json_with(self, vocabulary: &N) -> jstrict::Value {
176 on_sufficient_stack(move || {
177 let mut result = self.value.into_json_with(vocabulary);
178
179 if let Some(obj) = result.as_object_mut()
180 && let Some(index) = self.index
181 {
182 obj.insert("@index".into(), index.into_json());
183 }
184
185 result
186 })
187 }
188}