use proc_macro2::Span;
use serde_json;
use crate::common::{MacroError, MacroResult};
#[derive(Debug, Clone)]
pub struct DefaultValue {
pub raw_value: String,
pub value_type: DefaultValueType,
pub is_json: bool,
pub span: Option<Span>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DefaultValueType {
String(String),
Integer(i64),
Float(f64),
Boolean(bool),
Json(serde_json::Value),
CustomType(String),
Null,
}
pub struct DefaultValueParser;
impl DefaultValueParser {
pub fn parse(
raw_value: &str,
span: Option<Span>,
) -> MacroResult<DefaultValue> {
let trimmed_value = raw_value.trim();
if trimmed_value.is_empty() {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::String(String::new()),
is_json: false,
span,
});
}
if Self::is_json_format(trimmed_value) {
match serde_json::from_str::<serde_json::Value>(trimmed_value) {
Ok(json_value) => {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Json(json_value),
is_json: true,
span,
});
},
Err(json_err) => {
return Err(MacroError::default_value_parse_error(
&format!("JSON 解析失败: {json_err}"),
raw_value,
span.unwrap_or_else(Span::call_site),
));
},
}
}
match trimmed_value {
"true" => {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Boolean(true),
is_json: false,
span,
});
},
"false" => {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Boolean(false),
is_json: false,
span,
});
},
"null" => {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Null,
is_json: false,
span,
});
},
_ => {},
}
if let Ok(int_value) = trimmed_value.parse::<i64>() {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Integer(int_value),
is_json: false,
span,
});
}
if let Ok(float_value) = trimmed_value.parse::<f64>() {
if float_value.is_finite() {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::Float(float_value),
is_json: false,
span,
});
}
}
if Self::is_custom_type_expression(trimmed_value) {
return Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::CustomType(
trimmed_value.to_string(),
),
is_json: false,
span,
});
}
Ok(DefaultValue {
raw_value: raw_value.to_string(),
value_type: DefaultValueType::String(trimmed_value.to_string()),
is_json: false,
span,
})
}
fn is_json_format(value: &str) -> bool {
let trimmed = value.trim();
if trimmed.len() < 2 {
return false;
}
if trimmed.starts_with('{') && trimmed.ends_with('}') {
return true;
}
if trimmed.starts_with('[') && trimmed.ends_with(']') {
return true;
}
false
}
fn is_custom_type_expression(value: &str) -> bool {
let trimmed = value.trim();
if trimmed.is_empty() {
return false;
}
let has_namespace = trimmed.contains("::");
let has_method_call = trimmed.ends_with("()")
|| trimmed.contains("(") && trimmed.ends_with(")");
let common_constructors = [
"::new()",
"::default()",
"::with_default()",
"::with_capacity(",
"::empty()",
"::create()",
];
let has_common_constructor =
common_constructors.iter().any(|pattern| trimmed.contains(pattern));
let method_call_count = trimmed.matches("()").count()
+ trimmed.matches(')').count()
- trimmed.matches("()").count();
let has_chaining = method_call_count > 1;
has_namespace && has_method_call
|| has_common_constructor
|| has_chaining
}
}
impl DefaultValue {
pub fn type_name(&self) -> &'static str {
match &self.value_type {
DefaultValueType::String(_) => "String",
DefaultValueType::Integer(_) => "Integer",
DefaultValueType::Float(_) => "Float",
DefaultValueType::Boolean(_) => "Boolean",
DefaultValueType::Json(_) => "Json",
DefaultValueType::CustomType(_) => "CustomType",
DefaultValueType::Null => "Null",
}
}
pub fn is_numeric(&self) -> bool {
matches!(
self.value_type,
DefaultValueType::Integer(_) | DefaultValueType::Float(_)
)
}
pub fn is_string(&self) -> bool {
matches!(self.value_type, DefaultValueType::String(_))
}
pub fn is_boolean(&self) -> bool {
matches!(self.value_type, DefaultValueType::Boolean(_))
}
pub fn is_null(&self) -> bool {
matches!(self.value_type, DefaultValueType::Null)
}
pub fn is_custom_type(&self) -> bool {
matches!(self.value_type, DefaultValueType::CustomType(_))
}
}
impl PartialEq for DefaultValue {
fn eq(
&self,
other: &Self,
) -> bool {
self.raw_value == other.raw_value
&& self.value_type == other.value_type
&& self.is_json == other.is_json
}
}
impl MacroError {
pub fn default_value_parse_error(
reason: &str,
value: &str,
span: Span,
) -> Self {
MacroError::ParseError {
message: format!("默认值解析失败: {reason} (问题值: '{value}')"),
span: Some(span),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_string_default() {
let result = DefaultValueParser::parse("hello world", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert_eq!(default_value.raw_value, "hello world");
assert!(
matches!(default_value.value_type, DefaultValueType::String(ref s) if s == "hello world")
);
assert!(!default_value.is_json);
assert_eq!(default_value.type_name(), "String");
assert!(default_value.is_string());
}
#[test]
fn test_parse_integer_default() {
let result = DefaultValueParser::parse("42", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert_eq!(default_value.raw_value, "42");
assert!(matches!(
default_value.value_type,
DefaultValueType::Integer(42)
));
assert!(!default_value.is_json);
assert_eq!(default_value.type_name(), "Integer");
assert!(default_value.is_numeric());
}
#[test]
fn test_parse_negative_integer_default() {
let result = DefaultValueParser::parse("-100", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(matches!(
default_value.value_type,
DefaultValueType::Integer(-100)
));
assert!(default_value.is_numeric());
}
#[test]
fn test_parse_float_default() {
let result = DefaultValueParser::parse("3.14159", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert_eq!(default_value.raw_value, "3.14159");
#[allow(clippy::approx_constant)]
{
assert!(
matches!(default_value.value_type, DefaultValueType::Float(f) if (f - 3.14159).abs() < f64::EPSILON)
);
}
assert!(!default_value.is_json);
assert_eq!(default_value.type_name(), "Float");
assert!(default_value.is_numeric());
}
#[test]
fn test_parse_boolean_default() {
let result = DefaultValueParser::parse("true", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(matches!(
default_value.value_type,
DefaultValueType::Boolean(true)
));
assert_eq!(default_value.type_name(), "Boolean");
assert!(default_value.is_boolean());
let result = DefaultValueParser::parse("false", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(matches!(
default_value.value_type,
DefaultValueType::Boolean(false)
));
assert!(default_value.is_boolean());
}
#[test]
fn test_parse_null_default() {
let result = DefaultValueParser::parse("null", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(matches!(default_value.value_type, DefaultValueType::Null));
assert_eq!(default_value.type_name(), "Null");
assert!(default_value.is_null());
}
#[test]
fn test_parse_json_object_default() {
let json_str =
r#"{"key": "value", "number": 123, "nested": {"inner": true}}"#;
let result = DefaultValueParser::parse(json_str, None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert_eq!(default_value.raw_value, json_str);
assert!(default_value.is_json);
assert_eq!(default_value.type_name(), "Json");
if let DefaultValueType::Json(json_value) = &default_value.value_type {
assert_eq!(json_value["key"], "value");
assert_eq!(json_value["number"], 123);
assert_eq!(json_value["nested"]["inner"], true);
} else {
panic!("期望 JSON 类型");
}
}
#[test]
fn test_parse_json_array_default() {
let json_str = r#"["item1", "item2", {"key": "value"}]"#;
let result = DefaultValueParser::parse(json_str, None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(default_value.is_json);
if let DefaultValueType::Json(json_value) = &default_value.value_type {
assert!(json_value.is_array());
let array = json_value.as_array().unwrap();
assert_eq!(array.len(), 3);
assert_eq!(array[0], "item1");
assert_eq!(array[1], "item2");
assert_eq!(array[2]["key"], "value");
} else {
panic!("期望 JSON 类型");
}
}
#[test]
fn test_parse_invalid_json() {
let invalid_json = r#"{"invalid": json}"#; let result = DefaultValueParser::parse(invalid_json, None);
assert!(result.is_err());
if let Err(MacroError::ParseError { message, .. }) = result {
assert!(message.contains("JSON 解析失败"));
} else {
panic!("期望 ParseError");
}
}
#[test]
fn test_parse_empty_string() {
let result = DefaultValueParser::parse("", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(
matches!(default_value.value_type, DefaultValueType::String(ref s) if s.is_empty())
);
}
#[test]
fn test_parse_whitespace_string() {
let result = DefaultValueParser::parse(" ", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(
matches!(default_value.value_type, DefaultValueType::String(ref s) if s.is_empty())
);
}
#[test]
fn test_is_json_format() {
assert!(DefaultValueParser::is_json_format(r#"{"key": "value"}"#));
assert!(DefaultValueParser::is_json_format(r#"["item1", "item2"]"#));
assert!(DefaultValueParser::is_json_format("{}"));
assert!(DefaultValueParser::is_json_format("[]"));
assert!(DefaultValueParser::is_json_format(" { } "));
assert!(!DefaultValueParser::is_json_format("simple string"));
assert!(!DefaultValueParser::is_json_format("42"));
assert!(!DefaultValueParser::is_json_format("true"));
assert!(!DefaultValueParser::is_json_format("{"));
assert!(!DefaultValueParser::is_json_format("}"));
assert!(!DefaultValueParser::is_json_format(""));
assert!(!DefaultValueParser::is_json_format("a"));
}
#[test]
fn test_parse_complex_numbers() {
let result = DefaultValueParser::parse("0x42", None);
assert!(result.is_ok());
assert!(matches!(
result.unwrap().value_type,
DefaultValueType::String(_)
));
let result = DefaultValueParser::parse("1.23e-4", None);
assert!(result.is_ok());
assert!(matches!(
result.unwrap().value_type,
DefaultValueType::Float(_)
));
let result = DefaultValueParser::parse("999999999999999999999", None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(matches!(
default_value.value_type,
DefaultValueType::Integer(_)
| DefaultValueType::Float(_)
| DefaultValueType::String(_)
));
}
#[test]
fn test_parse_unicode_string() {
let unicode_str = "你好世界 🦀";
let result = DefaultValueParser::parse(unicode_str, None);
assert!(result.is_ok());
let default_value = result.unwrap();
assert!(
matches!(default_value.value_type, DefaultValueType::String(ref s) if s == unicode_str)
);
}
#[test]
fn test_parse_json_like_strings() {
let result = DefaultValueParser::parse("{incomplete", None);
assert!(result.is_ok());
assert!(matches!(
result.unwrap().value_type,
DefaultValueType::String(_)
));
let result = DefaultValueParser::parse("{'key': 'value'}", None);
assert!(result.is_err()); }
}