1use std::fmt;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
13pub enum PropertyType {
14 Boolean,
16 Integer,
18 Text,
20}
21
22#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
28pub enum PropertyValue {
29 Boolean(bool),
31 Integer(i64),
33 Text(String),
35}
36
37impl PropertyValue {
38 #[must_use]
44 pub const fn value_type(&self) -> PropertyType {
45 match self {
46 Self::Boolean(_value) => PropertyType::Boolean,
47 Self::Integer(_value) => PropertyType::Integer,
48 Self::Text(_value) => PropertyType::Text,
49 }
50 }
51}
52
53impl fmt::Display for PropertyValue {
54 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 Self::Boolean(value) => write!(formatter, "{value}"),
57 Self::Integer(value) => write!(formatter, "{value}"),
58 Self::Text(value) => formatter.write_str(value),
59 }
60 }
61}
62
63pub(crate) fn parse_value_token(token: &str) -> Result<PropertyValue, String> {
73 let trimmed = token.trim();
74 if trimmed == "true" {
75 return Ok(PropertyValue::Boolean(true));
76 }
77 if trimmed == "false" {
78 return Ok(PropertyValue::Boolean(false));
79 }
80 if let Ok(value) = trimmed.parse::<i64>() {
81 return Ok(PropertyValue::Integer(value));
82 }
83 parse_quoted(trimmed).map(PropertyValue::Text)
84}
85
86fn parse_quoted(token: &str) -> Result<String, String> {
88 let single = token
89 .strip_prefix('\'')
90 .and_then(|text| text.strip_suffix('\''));
91 let double = token
92 .strip_prefix('"')
93 .and_then(|text| text.strip_suffix('"'));
94 single
95 .or(double)
96 .map_or_else(|| Err(token.to_owned()), |value| Ok(value.to_owned()))
97}