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 { erased: ErasedResponse { owner, projection: project::<T, U>, payload: TypeId::of::<T>() }, payload: PhantomData }
65    }
66
67    pub fn ptr_eq(&self, other: &Self) -> bool {
68        Arc::ptr_eq(&self.erased.owner, &other.erased.owner)
69    }
70
71    pub fn try_unwrap(self) -> Result<T, Self> {
72        // Projected Owners Keep Their Loan; Only A Direct Payload Can Be Moved Out.
73        if !self.erased.owner.is::<T>() {
74            return Err(self);
75        }
76        let owner = match self.erased.owner.downcast::<T>() {
77            Ok(owner) => owner,
78            Err(_) => unreachable!("checked direct response owner type"),
79        };
80        Arc::try_unwrap(owner).map_err(Self::from_owner)
81    }
82
83    // Move the payload out, cloning only when the owner is shared or projected.
84    pub fn into_owned(self) -> T
85    where
86        T: Clone,
87    {
88        self.try_unwrap().unwrap_or_else(|response| (*response).clone())
89    }
90
91    pub fn into_erased(self) -> ErasedResponse {
92        self.erased
93    }
94}
95
96impl<T: Send + Sync + 'static> From<T> for Response<T> {
97    fn from(value: T) -> Self {
98        Self::new(value)
99    }
100}
101
102impl<T: Send + Sync + 'static> From<Arc<T>> for Response<T> {
103    fn from(value: Arc<T>) -> Self {
104        Self::from_owner(value)
105    }
106}
107
108impl<T: Send + Sync + 'static> Clone for Response<T> {
109    fn clone(&self) -> Self {
110        Self { erased: self.erased.clone(), payload: PhantomData }
111    }
112}
113
114impl<T: Send + Sync + 'static> Deref for Response<T> {
115    type Target = T;
116
117    fn deref(&self) -> &T {
118        self.erased.value::<T>().expect("response retains its declared payload")
119    }
120}
121
122impl<T: Send + Sync + 'static> AsRef<T> for Response<T> {
123    fn as_ref(&self) -> &T {
124        self
125    }
126}
127
128impl<T: Send + Sync + 'static> Borrow<T> for Response<T> {
129    fn borrow(&self) -> &T {
130        self
131    }
132}
133
134impl<T: fmt::Debug + Send + Sync + 'static> fmt::Debug for Response<T> {
135    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
136        self.deref().fmt(formatter)
137    }
138}
139
140impl<T: fmt::Display + Send + Sync + 'static> fmt::Display for Response<T> {
141    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
142        self.deref().fmt(formatter)
143    }
144}
145
146impl<T: PartialEq + Send + Sync + 'static> PartialEq for Response<T> {
147    fn eq(&self, other: &Self) -> bool {
148        self.deref() == other.deref()
149    }
150}
151
152impl<T: Eq + Send + Sync + 'static> Eq for Response<T> {}
153
154impl ErasedResponse {
155    pub fn restore<T: Send + Sync + 'static>(self) -> Option<Response<T>> {
156        // Typed Constructors Seal This Association; Restoration Must Not Run Borrow Code.
157        if self.payload != TypeId::of::<T>() {
158            return None;
159        }
160        Some(Response { erased: self, payload: PhantomData })
161    }
162
163    pub(super) fn value<T: Send + Sync + 'static>(&self) -> Option<&T> {
164        if self.payload != TypeId::of::<T>() {
165            return None;
166        }
167        (self.projection)(&*self.owner)?.downcast_ref::<T>()
168    }
169}
170
171/* === Public Functions === */
172
173/* === Private Functions === */
174
175fn project<T: Send + Sync + 'static, U: Borrow<T> + Send + Sync + 'static>(owner: &dyn Any) -> Option<&dyn Any> {
176    let owner = owner.downcast_ref::<U>()?;
177    Some(owner.borrow())
178}
179
180/* === Tests === */