tvm_ffi/extra/
unchanged.rs1use std::marker::PhantomData;
23
24use crate::any::{Any, AnyView, TryFromTemp};
25use crate::error::{Error, Result, TYPE_ERROR};
26use crate::tvm_ffi_sys::{TVMFFIAny, TVMFFITypeIndex};
27use crate::type_traits::{AnyCompatible, ContainerElement};
28
29#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
34pub struct Unchanged;
35
36unsafe impl AnyCompatible for Unchanged {
38 unsafe fn copy_to_any_view(_src: &Self, data: &mut TVMFFIAny) {
39 *data = TVMFFIAny::new();
40 data.type_index = TVMFFITypeIndex::kTVMFFIUnchanged as i32;
41 }
42
43 unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
44 Self::copy_to_any_view(&src, data);
45 }
46
47 unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
48 data.type_index == TVMFFITypeIndex::kTVMFFIUnchanged as i32
49 }
50
51 unsafe fn copy_from_any_view_after_check(_data: &TVMFFIAny) -> Self {
52 Self
53 }
54
55 unsafe fn move_from_any_after_check(_data: &mut TVMFFIAny) -> Self {
56 Self
57 }
58
59 unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> std::result::Result<Self, ()> {
60 Self::check_any_strict(data).then_some(Self).ok_or(())
61 }
62
63 fn type_str() -> std::string::String {
64 "Unchanged".into()
65 }
66}
67
68crate::impl_try_from_any!(Unchanged);
69
70#[repr(transparent)]
79pub struct UnchangedOr<T: ContainerElement = Any> {
80 data: Any,
81 _marker: PhantomData<T>,
82}
83
84impl<T: ContainerElement> UnchangedOr<T> {
85 #[inline]
87 pub fn unchanged() -> Self {
88 Self {
89 data: Unchanged.into(),
90 _marker: PhantomData,
91 }
92 }
93
94 #[inline]
96 pub fn changed(value: T) -> Self {
97 let mut raw = TVMFFIAny::new();
98 unsafe {
100 T::container_move_to_any(value, &mut raw);
101 Self {
102 data: Any::from_raw_ffi_any(raw),
103 _marker: PhantomData,
104 }
105 }
106 }
107
108 #[inline]
110 pub fn is_unchanged(&self) -> bool {
111 is_unchanged(&self.data)
112 }
113
114 #[inline]
116 pub fn unchanged_or_same_as(&self, original: &T) -> bool {
117 if self.is_unchanged() {
118 return true;
119 }
120 let mut raw = TVMFFIAny::new();
121 unsafe {
123 T::container_copy_to_any_view(original, &mut raw);
124 }
125 super::structural_common::same_shallow(raw, *self.data.as_raw_ffi_any())
126 }
127
128 #[inline]
130 pub fn into_option(self) -> Option<T> {
131 if self.is_unchanged() {
132 return None;
133 }
134 unsafe {
136 let mut raw = Any::into_raw_ffi_any(self.data);
137 Some(T::container_move_from_any_after_check(&mut raw))
138 }
139 }
140
141 #[inline]
143 pub fn value_or(self, original: T) -> T {
144 self.value_or_else(|| original)
145 }
146
147 #[inline]
149 pub fn value_or_else(self, original: impl FnOnce() -> T) -> T {
150 self.into_option().unwrap_or_else(original)
151 }
152
153 #[inline]
155 pub fn map<U: ContainerElement>(self, convert: impl FnOnce(T) -> U) -> UnchangedOr<U> {
156 match self.into_option() {
157 Some(value) => UnchangedOr::changed(convert(value)),
158 None => UnchangedOr::unchanged(),
159 }
160 }
161
162 #[inline]
164 pub fn try_map<U: ContainerElement, E>(
165 self,
166 convert: impl FnOnce(T) -> std::result::Result<U, E>,
167 ) -> std::result::Result<UnchangedOr<U>, E> {
168 match self.into_option() {
169 Some(value) => convert(value).map(UnchangedOr::changed),
170 None => Ok(UnchangedOr::unchanged()),
171 }
172 }
173
174 #[inline]
180 pub fn try_cast<U: ContainerElement>(self) -> Result<UnchangedOr<U>> {
181 if unsafe { UnchangedOr::<U>::check_any_strict(self.data.as_raw_ffi_any()) } {
182 Ok(UnchangedOr {
183 data: self.data,
184 _marker: PhantomData,
185 })
186 } else {
187 Err(Error::new(
188 TYPE_ERROR,
189 &format!(
190 "structural mutation result does not match {}",
191 U::container_type_str()
192 ),
193 "",
194 ))
195 }
196 }
197}
198
199impl UnchangedOr<Any> {
200 #[inline]
201 pub(crate) fn from_carrier(data: Any) -> Result<Self> {
202 if data.type_index() == TVMFFITypeIndex::kTVMFFIError as i32 {
203 return match Error::try_from(data) {
204 Ok(error) | Err(error) => Err(error),
205 };
206 }
207 Ok(Self {
208 data,
209 _marker: PhantomData,
210 })
211 }
212}
213
214impl<T: ContainerElement> Clone for UnchangedOr<T> {
215 #[inline]
216 fn clone(&self) -> Self {
217 Self {
218 data: self.data.clone(),
219 _marker: PhantomData,
220 }
221 }
222}
223
224unsafe impl<T: ContainerElement> AnyCompatible for UnchangedOr<T> {
228 unsafe fn copy_to_any_view(src: &Self, data: &mut TVMFFIAny) {
229 *data = *src.data.as_raw_ffi_any();
230 }
231
232 unsafe fn move_to_any(src: Self, data: &mut TVMFFIAny) {
233 *data = Any::into_raw_ffi_any(src.data);
234 }
235
236 unsafe fn check_any_strict(data: &TVMFFIAny) -> bool {
237 if T::CONTAINER_IS_ANY {
238 data.type_index != TVMFFITypeIndex::kTVMFFIError as i32
240 } else {
241 Unchanged::check_any_strict(data) || T::container_check_any_strict(data)
242 }
243 }
244
245 unsafe fn copy_from_any_view_after_check(data: &TVMFFIAny) -> Self {
246 if Unchanged::check_any_strict(data) {
247 return Self::unchanged();
248 }
249 Self::changed(T::container_copy_from_any_view_after_check(data))
251 }
252
253 unsafe fn move_from_any_after_check(data: &mut TVMFFIAny) -> Self {
254 Self {
255 data: Any::from_raw_ffi_any(std::mem::replace(data, TVMFFIAny::new())),
256 _marker: PhantomData,
257 }
258 }
259
260 unsafe fn try_cast_from_any_view(data: &TVMFFIAny) -> std::result::Result<Self, ()> {
261 if T::CONTAINER_IS_ANY && data.type_index == TVMFFITypeIndex::kTVMFFIError as i32 {
262 return Err(());
263 }
264 if Unchanged::check_any_strict(data) {
265 return Ok(Self::unchanged());
266 }
267 T::container_try_cast_from_any_view(data).map(Self::changed)
268 }
269
270 fn type_str() -> std::string::String {
271 format!("UnchangedOr<{}>", T::container_type_str())
272 }
273}
274
275impl<T: ContainerElement> TryFrom<Any> for UnchangedOr<T> {
276 type Error = Error;
277 #[inline]
278 fn try_from(value: Any) -> Result<Self> {
279 TryFromTemp::<Self>::try_from(value).map(TryFromTemp::into_value)
280 }
281}
282
283impl<'a, T: ContainerElement> TryFrom<AnyView<'a>> for UnchangedOr<T> {
284 type Error = Error;
285 #[inline]
286 fn try_from(value: AnyView<'a>) -> Result<Self> {
287 TryFromTemp::<Self>::try_from(value).map(TryFromTemp::into_value)
288 }
289}
290
291#[inline]
292pub(crate) fn is_unchanged(value: &Any) -> bool {
293 value.type_index() == TVMFFITypeIndex::kTVMFFIUnchanged as i32
294}