pepl_stdlib/modules/
convert.rs1use crate::error::StdlibError;
6use crate::module::StdlibModule;
7use crate::value::Value;
8
9pub struct ConvertModule;
11
12impl ConvertModule {
13 pub fn new() -> Self {
14 Self
15 }
16}
17
18impl Default for ConvertModule {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl StdlibModule for ConvertModule {
25 fn name(&self) -> &'static str {
26 "convert"
27 }
28
29 fn has_function(&self, function: &str) -> bool {
30 matches!(
31 function,
32 "to_string" | "to_number" | "parse_int" | "parse_float" | "to_bool"
33 )
34 }
35
36 fn call(&self, function: &str, args: Vec<Value>) -> Result<Value, StdlibError> {
37 match function {
38 "to_string" => self.to_string_fn(args),
39 "to_number" => self.to_number(args),
40 "parse_int" => self.parse_int(args),
41 "parse_float" => self.parse_float(args),
42 "to_bool" => self.to_bool(args),
43 _ => Err(StdlibError::unknown_function("convert", function)),
44 }
45 }
46}
47
48impl ConvertModule {
49 fn to_string_fn(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
52 if args.len() != 1 {
53 return Err(StdlibError::wrong_args("convert.to_string", 1, args.len()));
54 }
55 Ok(Value::String(format!("{}", args[0])))
56 }
57
58 fn to_number(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
65 if args.len() != 1 {
66 return Err(StdlibError::wrong_args("convert.to_number", 1, args.len()));
67 }
68 match &args[0] {
69 Value::Number(n) => Ok(Value::Number(*n).ok()),
70 Value::Bool(b) => Ok(Value::Number(if *b { 1.0 } else { 0.0 }).ok()),
71 Value::String(s) => match s.trim().parse::<f64>() {
72 Ok(n) if n.is_finite() => Ok(Value::Number(n).ok()),
73 _ => Ok(Value::String(format!("cannot convert '{}' to number", s)).err()),
74 },
75 other => {
76 Ok(Value::String(format!("cannot convert {} to number", other.type_name())).err())
77 }
78 }
79 }
80
81 fn parse_int(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
84 if args.len() != 1 {
85 return Err(StdlibError::wrong_args("convert.parse_int", 1, args.len()));
86 }
87 let s = extract_string("convert.parse_int", &args[0], 1)?;
88 match s.trim().parse::<i64>() {
89 Ok(n) => Ok(Value::Number(n as f64).ok()),
90 Err(_) => Ok(Value::String(format!("cannot parse '{}' as integer", s)).err()),
91 }
92 }
93
94 fn parse_float(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
96 if args.len() != 1 {
97 return Err(StdlibError::wrong_args(
98 "convert.parse_float",
99 1,
100 args.len(),
101 ));
102 }
103 let s = extract_string("convert.parse_float", &args[0], 1)?;
104 match s.trim().parse::<f64>() {
105 Ok(n) if n.is_finite() => Ok(Value::Number(n).ok()),
106 _ => Ok(Value::String(format!("cannot parse '{}' as float", s)).err()),
107 }
108 }
109
110 fn to_bool(&self, args: Vec<Value>) -> Result<Value, StdlibError> {
113 if args.len() != 1 {
114 return Err(StdlibError::wrong_args("convert.to_bool", 1, args.len()));
115 }
116 Ok(Value::Bool(args[0].is_truthy()))
117 }
118}
119
120fn extract_string<'a>(func: &str, val: &'a Value, pos: usize) -> Result<&'a str, StdlibError> {
123 match val {
124 Value::String(s) => Ok(s),
125 _ => Err(StdlibError::type_mismatch(
126 func,
127 pos,
128 "string",
129 val.type_name(),
130 )),
131 }
132}