1use crate::{SkewerCase, Resource, ResourceIdentifier, ResourceSelector, ResourceStub, FieldSelection, ResourcePath};
2use std::str::FromStr;
3use crate::error::Error;
4use crate::data::{DataSet, BinSrc, Meta};
5use serde::{Serialize,Deserialize};
6use std::collections::HashMap;
7use crate::parse::{parse_resource_property_value_selector, parse_resource_value_selector};
8use crate::status::Status;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ResourceValueSelector {
12 pub resource: ResourcePath,
13 pub property: ResourcePropertyValueSelector,
14}
15
16impl ResourceValueSelector {
17 pub fn new( resource: ResourcePath, property: ResourcePropertyValueSelector ) -> Self {
18 Self{
19 resource,
20 property
21 }
22 }
23}
24
25impl FromStr for ResourceValueSelector {
26 type Err = Error;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 let (leftover, selector ) = parse_resource_value_selector(s)?;
30
31 if !leftover.is_empty() {
32 return Err(format!("could not parse ResourceValueSelector: '{}' trailing portion '{}'", s, leftover).into() );
33 } else {
34 return Ok(selector?);
35 }
36 }
37}
38
39
40
41#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
42pub enum DataSetAspectSelector {
43 All,
44 Exact(String)
45}
46
47impl DataSetAspectSelector {
48 pub fn filter( &self, set: DataSet<BinSrc> ) -> ResourceValue {
49 match self {
50 DataSetAspectSelector::Exact(aspect) => {
51 let mut rtn = DataSet::new();
52 if set.contains_key(aspect) {
53 rtn.insert( aspect.clone(), set.get(aspect).expect(format!("expected aspect: {}", aspect).as_str() ).clone());
54 }
55 ResourceValue::DataSet(rtn)
56 }
57 DataSetAspectSelector::All => {
58 ResourceValue::DataSet(set)
59 }
60 }
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
65pub enum ResourcePropertyValueSelector {
66 None,
67 State{ aspect: DataSetAspectSelector, field: FieldValueSelector },
68 Status
69}
70
71impl ResourcePropertyValueSelector {
72
73 pub fn state() -> Self {
74 Self::State {
75 aspect: DataSetAspectSelector::All,
76 field: FieldValueSelector::All
77 }
78 }
79
80 pub fn state_aspect(aspect: &str) -> Self {
81 Self::State {
82 aspect: DataSetAspectSelector::Exact(aspect.to_string()),
83 field: FieldValueSelector::All
84 }
85 }
86
87 pub fn state_aspect_field(aspect: &str, field: &str) -> Self {
88 Self::State {
89 aspect: DataSetAspectSelector::Exact(aspect.to_string()),
90 field: FieldValueSelector::Meta(MetaFieldValueSelector::Exact(field.to_string()))
91 }
92 }
93
94 pub fn filter( &self, resource: Resource ) -> ResourceValue {
95 match self {
96 ResourcePropertyValueSelector::State { aspect: selector, field } => {
97 field.filter( selector.filter(resource.state) )
98 }
99 ResourcePropertyValueSelector::None => {
100 ResourceValue::None
101 }
102 ResourcePropertyValueSelector::Status => {
103 ResourceValue::None
104 }
105 }
106 }
107}
108
109impl FromStr for ResourcePropertyValueSelector {
110 type Err = Error;
111
112 fn from_str(s: &str) -> Result<Self, Self::Err> {
113 let (leftover,selector) = parse_resource_property_value_selector(s)?;
114 if !leftover.is_empty() {
115 Err(format!("could not parse entire ResourcePropertyValueSelector: {} because of remaining string: {}", s, leftover ).into())
116 } else {
117 Ok(selector?)
118 }
119 }
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
123pub enum FieldValueSelector {
124 All,
125 Meta(MetaFieldValueSelector)
126}
127
128impl FieldValueSelector {
129 pub fn filter( &self, selection: ResourceValue ) -> ResourceValue {
130
131 match self {
132 Self::All => {
133 if let ResourceValue::Meta(meta) = selection {
134 ResourceValue::Meta(meta)
135 } else {
136 selection
137 }
138 }
139 Self::Meta(selector) => {
140 if let ResourceValue::Meta(meta) = selection {
141 selector.filter(meta)
142 } else {
143 ResourceValue::None
144 }
145 }
146 }
147 }
148
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
152pub enum MetaFieldValueSelector {
153 All,
154 Exact(String)
155}
156
157impl MetaFieldValueSelector {
158 pub fn filter( &self, meta: Meta ) -> ResourceValue {
159 match self {
160 MetaFieldValueSelector::Exact(field) => {
161 if meta.contains_key(field) {
162 let value = meta.get(field).expect(format!("expecting field: {}",field).as_str() );
163 ResourceValue::String(value.clone())
164 } else {
165 ResourceValue::None
166 }
167 }
168 MetaFieldValueSelector::All => {
169 ResourceValue::Meta(meta)
170 }
171 }
172 }
173}
174
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub enum ResourceValue {
178 None,
179 DataSet(DataSet<BinSrc>),
180 BinSrc(BinSrc),
181 String(String),
182 Meta(Meta),
183 Resource(Resource),
184 Status(Status)
185}
186
187impl ToString for ResourceValue {
188 fn to_string(&self) -> String {
189 match self {
190 ResourceValue::None => {
191 "".to_string()
192 }
193 ResourceValue::DataSet(data) => {
194 let mut rtn = String::new();
195 for (k,v) in data {
196 match v {
197 BinSrc::Memory(bin) => {
198 rtn.push_str( String::from_utf8(bin.to_vec()).unwrap_or("UTF ERROR!".to_string() ).as_str() )
199 }
200 }
201 }
202 rtn
203 }
204 ResourceValue::BinSrc(v) => {
205 match v {
206 BinSrc::Memory(bin) => {
207 String::from_utf8(bin.to_vec()).unwrap_or("UTF ERROR!".to_string() )
208 }
209 }
210
211 }
212 ResourceValue::String(string) => {
213 string.clone()
214 }
215 ResourceValue::Meta(_) => {
216 "Meta printing not supported yet.".to_string()
217 }
218 ResourceValue::Resource(_) => {
219 "Resource string printing not supported yet.".to_string()
220 }
221 ResourceValue::Status(status) => {
222 status.to_string()
223 }
224 }
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct ResourceValues<R> {
230 pub resource: R,
231 pub values: HashMap<ResourcePropertyValueSelector,ResourceValue>
232}
233
234impl <R> ResourceValues <R> {
235
236 pub fn empty(resource: R ) -> Self {
237 Self {
238 resource,
239 values: HashMap::new()
240 }
241 }
242
243 pub fn new(resource: R, values: HashMap<ResourcePropertyValueSelector,ResourceValue>) -> Self {
244 Self {
245 resource,
246 values
247 }
248 }
249
250 pub fn with<T>(self, resource: T) -> ResourceValues<T> {
251 ResourceValues{
252 resource,
253 values: self.values
254 }
255 }
256}
257
258