sapio_base/effects/
reverse_path.rs

1// Copyright Judica, Inc 2021
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4//  License, v. 2.0. If a copy of the MPL was not distributed with this
5//  file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7//! general non-parameter compilation state required by all contracts
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use std::marker::PhantomData;
11use std::sync::Arc;
12/// Used to Build a Shared Path for all children of a given context.
13#[derive(
14    Serialize, Deserialize, JsonSchema, Debug, Clone, Hash, PartialEq, PartialOrd, Ord, Eq,
15)]
16#[serde(try_from = "Y")]
17#[serde(into = "Y")]
18#[serde(
19    bound = "T: Clone, Y: Serialize + for<'d> Deserialize<'d> + JsonSchema + std::fmt::Debug + Clone, Y: Serialize + From<Self>, Self: TryFrom<Y>, <Self as TryFrom<Y>>::Error : std::fmt::Display"
20)]
21pub struct ReversePath<T, Y = String> {
22    past: Option<Arc<ReversePath<T, Y>>>,
23    this: T,
24    _pd: PhantomData<Y>,
25}
26
27/// RPI = ReversePathIterator
28/// This simplifies iterating over a reversepath.
29pub struct RPI<'a, T, Y> {
30    inner: Option<&'a ReversePath<T, Y>>,
31}
32
33impl<'a, T, Y> Iterator for RPI<'a, T, Y> {
34    // we will be counting with usize
35    type Item = &'a T;
36
37    // next() is the only required method
38    fn next(&mut self) -> Option<Self::Item> {
39        let ret = self.inner.map(|x| &x.this);
40        match self.inner.map(|x| x.past.as_ref()) {
41            Some(Some(x)) => {
42                self.inner = Some(x);
43            }
44            _ => {
45                self.inner = None;
46            }
47        }
48        ret
49    }
50}
51
52use std::convert::TryFrom;
53impl<T, Y> TryFrom<Vec<T>> for ReversePath<T, Y> {
54    type Error = &'static str;
55    fn try_from(v: Vec<T>) -> Result<Self, Self::Error> {
56        match v
57            .into_iter()
58            .fold(None, |x, v| Some(Self::push(x, v)))
59            .map(Arc::try_unwrap)
60        {
61            Some(Ok(r)) => Ok(r),
62            _ => Err("Reverse Path must have at least one element."),
63        }
64    }
65}
66impl<T: Clone, Y> From<ReversePath<T, Y>> for Vec<T> {
67    fn from(r: ReversePath<T, Y>) -> Self {
68        let mut v: Vec<T> = r.iter().cloned().collect();
69        v.reverse();
70        v
71    }
72}
73impl<T: Clone, Y> From<T> for ReversePath<T, Y> {
74    fn from(this: T) -> Self {
75        ReversePath {
76            past: None,
77            this,
78            _pd: Default::default(),
79        }
80    }
81}
82/// Helper for making a ReversePath.
83pub struct MkReversePath<T, Y>(Option<Arc<ReversePath<T, Y>>>);
84impl<T, Y> MkReversePath<T, Y> {
85    /// Pop open a ReversePath, assuming one exists.
86    pub fn unwrap(self) -> Arc<ReversePath<T, Y>> {
87        if let Some(x) = self.0 {
88            x
89        } else {
90            panic!("Vector must have at least one root path")
91        }
92    }
93}
94impl<T, Y> From<Vec<T>> for MkReversePath<T, Y> {
95    fn from(v: Vec<T>) -> Self {
96        let mut rp: Option<Arc<ReversePath<T, Y>>> = None;
97        for val in v {
98            let new: Arc<ReversePath<T, Y>> = ReversePath::push(rp, val);
99            rp = Some(new);
100        }
101        MkReversePath(rp)
102    }
103}
104impl<T, Y> ReversePath<T, Y> {
105    /// Add an element to a ReversePath
106    pub fn push(v: Option<Arc<ReversePath<T, Y>>>, s: T) -> Arc<ReversePath<T, Y>> {
107        Arc::new(Self::push_owned(v, s))
108    }
109    /// Add an element to a ReversePath and do not wrap in Arc
110    pub fn push_owned(v: Option<Arc<ReversePath<T, Y>>>, s: T) -> ReversePath<T, Y> {
111        ReversePath::<T, Y> {
112            past: v,
113            this: s,
114            _pd: Default::default(),
115        }
116    }
117    /// iterate over a reversepath
118    pub fn iter(&self) -> RPI<'_, T, Y> {
119        RPI { inner: Some(self) }
120    }
121}
122
123#[cfg(test)]
124mod test {
125    use super::*;
126    use std::convert::TryInto;
127    #[test]
128    fn test_reverse_path_into_vec() {
129        assert_eq!(
130            Vec::<i64>::from(
131                ReversePath::<i64, Vec<i64>>::push(Some(ReversePath::push(None, 1i64)), 5i64,)
132                    .as_ref()
133                    .clone()
134            ),
135            vec![1i64, 5]
136        );
137    }
138    #[test]
139    fn test_reverse_path_from_vec() {
140        assert_eq!(
141            ReversePath::<i64, Vec<i64>>::push(Some(ReversePath::push(None, 1i64)), 5,)
142                .as_ref()
143                .clone(),
144            vec![1i64, 5].try_into().unwrap()
145        );
146    }
147    #[test]
148    fn test_reverse_path_into_serde() -> Result<(), Box<dyn std::error::Error>> {
149        assert_eq!(
150            serde_json::to_string(
151                ReversePath::<i64, Vec<i64>>::push(Some(ReversePath::push(None, 1i64)), 5,)
152                    .as_ref()
153            )?,
154            "[1,5]"
155        );
156        Ok(())
157    }
158    #[test]
159    fn test_reverse_path_from_serde() -> Result<(), Box<dyn std::error::Error>> {
160        let v: ReversePath<i64, Vec<i64>> = serde_json::from_str("[1,5]")?;
161        assert_eq!(
162            ReversePath::push(Some(ReversePath::push(None, 1i64)), 5,).as_ref(),
163            &v
164        );
165        Ok(())
166    }
167
168    #[test]
169    fn test_eq() {
170        assert_eq!(
171            ReversePath::<i64, Vec<i64>>::push(Some(ReversePath::push(None, 1i64)), 5,),
172            ReversePath::push(Some(ReversePath::push(None, 1i64)), 5,)
173        );
174        let a = (0..100)
175            .fold(None, |x, y| Some(ReversePath::<i64, Vec<i64>>::push(x, y)))
176            .unwrap();
177        assert_eq!(a, a.clone());
178        let b = (0..100)
179            .fold(None, |x, y| Some(ReversePath::push(x, y)))
180            .unwrap();
181        assert_eq!(a, b);
182    }
183    #[test]
184    fn test_neq() {
185        assert_ne!(
186            ReversePath::<i64, Vec<i64>>::push(Some(ReversePath::push(None, 1i64)), 5,),
187            ReversePath::push(Some(ReversePath::push(None, 0i64)), 5,)
188        );
189        let a = (0..100)
190            .fold(None, |x, y| Some(ReversePath::<i64, Vec<i64>>::push(x, y)))
191            .unwrap();
192        let b = (0..101)
193            .fold(None, |x, y| Some(ReversePath::<i64, Vec<i64>>::push(x, y)))
194            .unwrap();
195        assert_ne!(a, b);
196    }
197}