sapio_base/effects/
path_fragment.rs1use crate::reverse_path::ReversePath;
9use crate::serialization_helpers::SArc;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12
13use std::convert::TryFrom;
14use std::str::FromStr;
15use std::sync::Arc;
16
17#[derive(
19 Serialize, Deserialize, Debug, Hash, Eq, PartialEq, JsonSchema, Clone, PartialOrd, Ord,
20)]
21#[serde(into = "String")]
22#[serde(try_from = "&str")]
23pub enum PathFragment {
24 Root,
26 Cloned,
28 Action,
30 FinishFn,
32 CondCompIf,
34 Guard,
36 Next,
38 Suggested,
40 DefaultEffect,
42 Effects,
44 Metadata,
46 Branch(u64),
48 Named(SArc<String>),
50}
51
52impl From<PathFragment> for String {
53 fn from(a: PathFragment) -> Self {
54 Self::from(&a)
55 }
56}
57impl From<&PathFragment> for String {
58 fn from(a: &PathFragment) -> Self {
59 match a {
60 PathFragment::Root => "@root".into(),
61 PathFragment::Cloned => "@cloned".into(),
62 PathFragment::Action => "@action".into(),
63 PathFragment::FinishFn => "@finish_fn".into(),
64 PathFragment::CondCompIf => "@cond_comp_if".into(),
65 PathFragment::Guard => "@guard".into(),
66 PathFragment::Next => "@next".into(),
67 PathFragment::Suggested => "@suggested".into(),
68 PathFragment::DefaultEffect => "@default_effect".into(),
69 PathFragment::Effects => "@effects".into(),
70 PathFragment::Metadata => "@metadata".into(),
71 PathFragment::Branch(u) => format!("#{}", u),
72 PathFragment::Named(SArc(a)) => a.as_ref().clone(),
73 }
74 }
75}
76
77#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, JsonSchema, Clone)]
79pub enum ValidFragmentError {
80 BranchParseError,
82 BadName(SArc<String>),
84 InvalidReversePath(&'static str),
86}
87
88impl std::error::Error for ValidFragmentError {}
89impl std::fmt::Display for ValidFragmentError {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
91 std::fmt::Debug::fmt(self, f)
92 }
93}
94use std::num::ParseIntError;
95impl From<ParseIntError> for ValidFragmentError {
96 fn from(_u: ParseIntError) -> ValidFragmentError {
97 ValidFragmentError::BranchParseError
98 }
99}
100
101impl TryFrom<Arc<String>> for PathFragment {
102 type Error = ValidFragmentError;
103 fn try_from(s: Arc<String>) -> Result<Self, Self::Error> {
104 Self::try_from(s.as_ref().as_str())
105 }
106}
107impl TryFrom<&str> for PathFragment {
108 type Error = ValidFragmentError;
109 fn try_from(s: &str) -> Result<Self, Self::Error> {
110 Ok(match s {
111 "@root" => PathFragment::Root,
112 "@cloned" => PathFragment::Cloned,
113 "@action" => PathFragment::Action,
114 "@finish_fn" => PathFragment::FinishFn,
115 "@cond_comp_if" => PathFragment::CondCompIf,
116 "@guard" => PathFragment::Guard,
117 "@next" => PathFragment::Next,
118 "@suggested" => PathFragment::Suggested,
119 "@default_effect" => PathFragment::DefaultEffect,
120 "@effects" => PathFragment::Effects,
121 "@metadata" => PathFragment::Metadata,
122 n if n.starts_with('#') => PathFragment::Branch(FromStr::from_str(&n[1..])?),
123 n if n.chars().all(|x| x.is_ascii_alphanumeric() || x == '_') => {
124 PathFragment::Named(SArc(Arc::new(s.into())))
125 }
126 _ => return Err(ValidFragmentError::BadName(SArc(Arc::new(s.into())))),
127 })
128 }
129}
130
131impl From<ReversePath<PathFragment>> for String {
132 fn from(r: ReversePath<PathFragment>) -> String {
133 let mut v: Vec<String> = r.iter().cloned().map(String::from).collect();
134 v.reverse();
135 v.join("/")
136 }
137}
138
139impl TryFrom<&str> for ReversePath<PathFragment> {
140 type Error = ValidFragmentError;
141 fn try_from(r: &str) -> Result<ReversePath<PathFragment>, Self::Error> {
142 let frags = r
143 .split('/')
144 .map(PathFragment::try_from)
145 .collect::<Result<Vec<_>, _>>()?;
146 ReversePath::try_from(frags).map_err(ValidFragmentError::InvalidReversePath)
147 }
148}
149
150impl TryFrom<String> for ReversePath<PathFragment> {
151 type Error = ValidFragmentError;
152 fn try_from(r: String) -> Result<ReversePath<PathFragment>, Self::Error> {
153 Self::try_from(r.as_ref())
154 }
155}