Skip to main content

harmos_sdk/operations/
response.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10// Response Handles Retain Their Original Payload Owner Through Delivery And Encoding.
11
12/* === Modules === */
13
14/* === Re-Exports === */
15
16/* === Imports === */
17
18// Standard Library Imports
19use std::any::{Any, TypeId};
20use std::borrow::Borrow;
21use std::fmt;
22use std::marker::PhantomData;
23use std::ops::Deref;
24use std::sync::Arc;
25// Third Party Imports
26
27// Local Imports
28
29/* === Constants === */
30
31/* === Macros === */
32
33/* === Type Aliases === */
34
35type Projection = fn(&dyn Any) -> Option<&dyn Any>;
36
37/* === Structs === */
38
39pub struct Response<T: Send + Sync + 'static> {
40    erased: ErasedResponse,
41    payload: PhantomData<fn() -> T>,
42}
43
44// Only Typed Constructors Can Associate An Owner With Its Payload Projection.
45#[derive(Clone)]
46pub struct ErasedResponse {
47    owner: Arc<dyn Any + Send + Sync>,
48    projection: Projection,
49    payload: TypeId,
50}
51
52/* === Enums === */
53
54/* === Traits === */
55
56/* === Implementations === */
57
58impl<T: Send + Sync + 'static> Response<T> {
59    pub fn new(value: T) -> Self {
60        Self::from_owner(Arc::new(value))
61    }
62
63    pub fn from_owner<U: Borrow<T> + Send + Sync + 'static>(owner: Arc<U>) -> Self {
64        Self {
65            erased: ErasedResponse {
66                owner,
67                projection: project::<T, U>,
68                payload: TypeId::of::<T>(),
69            },
70            payload: PhantomData,
71        }
72    }
73
74    pub fn ptr_eq(&self, other: &Self) -> bool {
75        Arc::ptr_eq(&self.erased.owner, &other.erased.owner)
76    }
77
78    pub fn try_unwrap(self) -> Result<T, Self> {
79        // Projected Owners Keep Their Loan; Only A Direct Payload Can Be Moved Out.
80        if !self.erased.owner.is::<T>() {
81            return Err(self);
82        }
83        let owner = match self.erased.owner.downcast::<T>() {
84            Ok(owner) => owner,
85            Err(_) => unreachable!("checked direct response owner type"),
86        };
87        Arc::try_unwrap(owner).map_err(Self::from_owner)
88    }
89
90    // Move the payload out, cloning only when the owner is shared or projected.
91    pub fn into_owned(self) -> T
92    where
93        T: Clone,
94    {
95        self.try_unwrap().unwrap_or_else(|response| (*response).clone())
96    }
97
98    pub fn into_erased(self) -> ErasedResponse {
99        self.erased
100    }
101}
102
103impl<T: Send + Sync + 'static> From<T> for Response<T> {
104    fn from(value: T) -> Self {
105        Self::new(value)
106    }
107}
108
109impl<T: Send + Sync + 'static> From<Arc<T>> for Response<T> {
110    fn from(value: Arc<T>) -> Self {
111        Self::from_owner(value)
112    }
113}
114
115impl<T: Send + Sync + 'static> Clone for Response<T> {
116    fn clone(&self) -> Self {
117        Self {
118            erased: self.erased.clone(),
119            payload: PhantomData,
120        }
121    }
122}
123
124impl<T: Send + Sync + 'static> Deref for Response<T> {
125    type Target = T;
126
127    fn deref(&self) -> &T {
128        self.erased.value::<T>().expect("response retains its declared payload")
129    }
130}
131
132impl<T: Send + Sync + 'static> AsRef<T> for Response<T> {
133    fn as_ref(&self) -> &T {
134        self
135    }
136}
137
138impl<T: Send + Sync + 'static> Borrow<T> for Response<T> {
139    fn borrow(&self) -> &T {
140        self
141    }
142}
143
144impl<T: fmt::Debug + Send + Sync + 'static> fmt::Debug for Response<T> {
145    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
146        self.deref().fmt(formatter)
147    }
148}
149
150impl<T: fmt::Display + Send + Sync + 'static> fmt::Display for Response<T> {
151    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
152        self.deref().fmt(formatter)
153    }
154}
155
156impl<T: PartialEq + Send + Sync + 'static> PartialEq for Response<T> {
157    fn eq(&self, other: &Self) -> bool {
158        self.deref() == other.deref()
159    }
160}
161
162impl<T: Eq + Send + Sync + 'static> Eq for Response<T> {}
163
164impl ErasedResponse {
165    pub fn restore<T: Send + Sync + 'static>(self) -> Option<Response<T>> {
166        // Typed Constructors Seal This Association; Restoration Must Not Run Borrow Code.
167        if self.payload != TypeId::of::<T>() {
168            return None;
169        }
170        Some(Response { erased: self, payload: PhantomData })
171    }
172
173    pub(super) fn value<T: Send + Sync + 'static>(&self) -> Option<&T> {
174        if self.payload != TypeId::of::<T>() {
175            return None;
176        }
177        (self.projection)(&*self.owner)?.downcast_ref::<T>()
178    }
179}
180
181/* === Public Functions === */
182
183/* === Private Functions === */
184
185fn project<T: Send + Sync + 'static, U: Borrow<T> + Send + Sync + 'static>(owner: &dyn Any) -> Option<&dyn Any> {
186    let owner = owner.downcast_ref::<U>()?;
187    Some(owner.borrow())
188}
189
190/* === Tests === */