1use crate::error::{DcsvError, DcsvResult};
6use regex::Regex;
7use std::{fmt::Display, str::FromStr};
8
9pub const LIMITER_ATTRIBUTE_LEN: usize = 4;
11
12#[derive(Clone, Eq, PartialEq, PartialOrd, Debug)]
21pub enum Value {
22 Number(isize),
23 Text(String),
24}
25
26impl Value {
27 pub fn get_type(&self) -> ValueType {
31 match self {
32 Self::Number(_) => ValueType::Number,
33 Self::Text(_) => ValueType::Text,
34 }
35 }
36 pub fn from_str(src: &str, value_type: ValueType) -> DcsvResult<Self> {
40 Ok(match value_type {
41 ValueType::Number => {
42 if src.is_empty() {
44 return Ok(Value::Number(0));
45 }
46
47 let src_number = src.parse::<isize>().map_err(|_| {
48 DcsvError::InvalidValueType(format!("\"{}\" is not a valid number", src))
49 })?;
50 Value::Number(src_number)
51 }
52 ValueType::Text => Value::Text(src.to_string()),
53 })
54 }
55
56 pub fn empty(value_type: ValueType) -> Self {
62 match value_type {
63 ValueType::Number => Self::Number(0),
64 ValueType::Text => Self::Text(String::new()),
65 }
66 }
67}
68
69impl Default for Value {
70 fn default() -> Self {
71 Self::Text(String::new())
72 }
73}
74
75impl std::fmt::Display for Value {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 let out = match self {
78 Self::Number(num) => num.to_string(),
79 Self::Text(txt) => txt.to_string(),
80 };
81 write!(f, "{}", out)
82 }
83}
84
85#[derive(Default, Clone, Debug)]
95pub struct ValueLimiter {
96 value_type: ValueType,
98 default: Option<Value>,
99 variant: Option<Vec<Value>>,
100 pattern: Option<Regex>, }
102
103impl Display for ValueLimiter {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 writeln!(f, "type : {}", self.value_type)?;
106 if let Some(var) = &self.variant {
107 writeln!(f, "default value : {:?}", &var)?;
108 }
109 if let Some(var) = &self.variant {
110 write!(f, "variants : {:?}", var)
111 } else if let Some(var) = &self.pattern {
112 write!(f, "pattern : {:?}", var)
113 } else {
114 write!(f, "")
115 }
116 }
117}
118
119impl ValueLimiter {
120 pub fn is_convertible(&self, value: &Value) -> Option<ValueType> {
122 match self.value_type {
125 ValueType::Number => {
126 if let Value::Text(text) = value {
127 if text.is_empty() {
129 return Some(ValueType::Number);
130 }
131
132 match text.parse::<isize>() {
134 Ok(_) => Some(ValueType::Number),
135 Err(_) => None,
136 }
137 } else {
138 Some(ValueType::Number)
140 }
141 }
142 ValueType::Text => Some(ValueType::Text),
143 }
144 }
145
146 pub fn qualify(&self, value: &Value) -> bool {
148 if value.get_type() != self.get_type() {
149 return false;
150 }
151 match value {
152 Value::Number(num) => {
153 if let Some(variant) = self.variant.as_ref() {
154 variant.contains(value)
155 } else if let Some(pattern) = self.pattern.as_ref() {
156 pattern.is_match(&num.to_string())
157 } else {
158 true
159 }
160 }
161 Value::Text(text) => {
162 if let Some(variant) = self.variant.as_ref() {
163 variant.contains(value)
164 } else if let Some(pattern) = self.pattern.as_ref() {
165 pattern.is_match(text)
166 } else {
167 true
168 }
169 }
170 }
171 }
172
173 pub fn from_line(attributes: &[impl AsRef<str>]) -> DcsvResult<Self> {
181 let attributes: Vec<&str> = attributes.iter().map(|s| s.as_ref()).collect();
182 if attributes.len() != LIMITER_ATTRIBUTE_LEN {
183 return Err(DcsvError::InvalidRowData(format!(
184 "Schema row has insufficient columns \n= {:?}",
185 attributes
186 )));
187 }
188 let mut limiter = Self::default();
189 let vt = ValueType::from_str(attributes[0])?;
190 let default = attributes[1];
191 let variants = attributes[2];
192 let pattern = attributes[3];
193 limiter.set_type(vt);
194
195 if !default.is_empty() {
197 let default = Value::from_str(default, vt)?;
198
199 if !variants.is_empty() {
201 let mut values = vec![];
202 for var in variants.split_whitespace() {
203 values.push(Value::from_str(var, vt)?);
204 }
205 limiter.set_variant(default, &values)?;
206 } else if !pattern.is_empty() {
207 limiter.set_pattern(
209 default,
210 Regex::new(pattern).expect("Failed to create pattern"),
211 )?;
212 } else {
213 limiter.default = Some(default);
214 }
215 } else {
216 if !pattern.is_empty() || !variants.is_empty() {
218 return Err(DcsvError::InvalidLimiter(
219 "Either pattern or variants needs default value to be valid".to_string(),
220 ));
221 }
222 }
223 Ok(limiter)
224 }
225
226 pub fn get_type(&self) -> ValueType {
228 self.value_type
229 }
230
231 pub fn set_type(&mut self, column_type: ValueType) {
233 self.value_type = column_type;
234 }
235
236 pub fn get_default(&self) -> Option<&Value> {
238 self.default.as_ref()
239 }
240
241 pub fn get_variant(&self) -> Option<&Vec<Value>> {
243 self.variant.as_ref()
244 }
245
246 pub fn set_variant(&mut self, default: Value, variants: &[Value]) -> DcsvResult<()> {
248 if !variants.contains(&default) {
249 return Err(DcsvError::InvalidLimiter(
250 "Default value should be among one of variants".to_string(),
251 ));
252 }
253 self.default.replace(default);
254 self.variant.replace(variants.to_vec());
255 Ok(())
256 }
257
258 pub fn get_pattern(&self) -> Option<&Regex> {
260 self.pattern.as_ref()
261 }
262
263 pub fn set_pattern(&mut self, default: Value, pattern: Regex) -> DcsvResult<()> {
265 if !pattern.is_match(&default.to_string()) {
266 return Err(DcsvError::InvalidLimiter(
267 "Default value should match pattern".to_string(),
268 ));
269 }
270 self.default.replace(default);
271 self.pattern.replace(pattern);
272 Ok(())
273 }
274}
275
276#[derive(Clone, Copy, PartialEq, Debug)]
278pub enum ValueType {
279 Number,
280 Text,
281}
282
283impl std::fmt::Display for ValueType {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 write!(
286 f,
287 "{}",
288 match self {
289 Self::Number => "Number",
290 Self::Text => "Text",
291 }
292 )
293 }
294}
295
296impl std::str::FromStr for ValueType {
297 type Err = DcsvError;
298
299 fn from_str(s: &str) -> Result<Self, Self::Err> {
301 match s.to_lowercase().as_str() {
302 "number" => Ok(Self::Number),
303 "text" => Ok(Self::Text),
304 _ => Err(DcsvError::InvalidValueType(
305 "Value type should be either number or text".to_string(),
306 )),
307 }
308 }
309}
310
311impl Default for ValueType {
312 fn default() -> Self {
313 Self::Text
314 }
315}