@@ -4,22 +4,128 @@ use std::{
44 str:: FromStr ,
55} ;
66
7+ use base64:: Engine ;
8+ use regex:: Regex ;
79use serde_cbor:: value:: { Value , from_value} ;
810use serde_json:: Value as JsonValue ;
11+ use slicestring:: Slice ;
912
1013use crate :: {
1114 error:: RadError ,
1215 hash_functions:: { self , RadonHashFunctions } ,
1316 types:: {
14- RadonType , RadonTypes , array:: RadonArray , boolean:: RadonBoolean , bytes:: RadonBytes ,
15- float:: RadonFloat , integer:: RadonInteger , map:: RadonMap , string:: RadonString ,
17+ RadonType , RadonTypes ,
18+ array:: RadonArray ,
19+ boolean:: RadonBoolean ,
20+ bytes:: { RadonBytes , RadonBytesEncoding } ,
21+ float:: RadonFloat ,
22+ integer:: RadonInteger ,
23+ map:: RadonMap ,
24+ string:: RadonString ,
1625 } ,
1726} ;
1827
1928const MAX_DEPTH : u8 = 20 ;
2029const DEFAULT_THOUSANDS_SEPARATOR : & str = "," ;
2130const DEFAULT_DECIMAL_SEPARATOR : & str = "." ;
2231
32+ pub fn as_bool ( input : & RadonString ) -> Result < RadonBoolean , RadError > {
33+ let str_value = radon_trim ( input) ;
34+ bool:: from_str ( & str_value)
35+ . map ( RadonBoolean :: from)
36+ . map_err ( Into :: into)
37+ }
38+
39+ pub fn as_bytes ( input : & RadonString , args : & Option < Vec < Value > > ) -> Result < RadonBytes , RadError > {
40+ let wrong_args = || RadError :: WrongArguments {
41+ input_type : RadonString :: radon_type_name ( ) ,
42+ operator : "AsBytes" . to_string ( ) ,
43+ args : args. to_owned ( ) . unwrap_or ( Vec :: < Value > :: default ( ) ) . to_vec ( ) ,
44+ } ;
45+ let mut input_string = input. value ( ) ;
46+ if input_string. starts_with ( "0x" ) {
47+ input_string = input_string. slice ( 2 ..) ;
48+ }
49+ if input_string. len ( ) % 2 != 0 {
50+ input_string. insert ( 0 , '0' ) ;
51+ }
52+ let mut bytes_encoding = RadonBytesEncoding :: Hex ;
53+ match args {
54+ Some ( args) => {
55+ if args. len ( ) > 0 {
56+ let arg = args. first ( ) . ok_or_else ( wrong_args) ?. to_owned ( ) ;
57+ let bytes_encoding_u8 = from_value :: < u8 > ( arg) . map_err ( |_| wrong_args ( ) ) ?;
58+ bytes_encoding =
59+ RadonBytesEncoding :: try_from ( bytes_encoding_u8) . map_err ( |_| wrong_args ( ) ) ?;
60+ }
61+ }
62+ _ => ( ) ,
63+ }
64+ match bytes_encoding {
65+ RadonBytesEncoding :: Hex => Ok ( RadonBytes :: from (
66+ hex:: decode ( input_string. as_str ( ) ) . map_err ( |_err| RadError :: Decode {
67+ from : "RadonString" ,
68+ to : "RadonBytes" ,
69+ } ) ?,
70+ ) ) ,
71+ RadonBytesEncoding :: Base64 => Ok ( RadonBytes :: from (
72+ base64:: engine:: general_purpose:: STANDARD
73+ . decode ( input. value ( ) )
74+ . map_err ( |_err| RadError :: Decode {
75+ from : "RadonString" ,
76+ to : "RadonBytes" ,
77+ } ) ?,
78+ ) ) ,
79+ RadonBytesEncoding :: Utf8 => Ok ( RadonBytes :: from ( input. value ( ) . as_bytes ( ) . to_vec ( ) ) ) ,
80+ }
81+ }
82+
83+ /// Converts a `RadonString` into a `RadonFloat`, provided that the input string actually represents
84+ /// a valid floating point number.
85+ pub fn as_float ( input : & RadonString , args : & Option < Vec < Value > > ) -> Result < RadonFloat , RadError > {
86+ f64:: from_str ( & to_numeric_string (
87+ input,
88+ args. as_deref ( ) . unwrap_or_default ( ) ,
89+ ) )
90+ . map ( RadonFloat :: from)
91+ . map_err ( Into :: into)
92+ }
93+
94+ /// Converts a `RadonString` into a `RadonFloat`, provided that the input string actually represents
95+ /// a valid integer number.
96+ pub fn as_integer (
97+ input : & RadonString ,
98+ args : & Option < Vec < Value > > ,
99+ ) -> Result < RadonInteger , RadError > {
100+ i128:: from_str ( & to_numeric_string (
101+ input,
102+ args. as_deref ( ) . unwrap_or_default ( ) ,
103+ ) )
104+ . map ( RadonInteger :: from)
105+ . map_err ( Into :: into)
106+ }
107+
108+ pub fn hash ( input : & RadonString , args : & [ Value ] ) -> Result < RadonString , RadError > {
109+ let wrong_args = || RadError :: WrongArguments {
110+ input_type : RadonString :: radon_type_name ( ) ,
111+ operator : "Hash" . to_string ( ) ,
112+ args : args. to_vec ( ) ,
113+ } ;
114+
115+ let input_string = input. value ( ) ;
116+ let input_bytes = input_string. as_bytes ( ) ;
117+
118+ let arg = args. first ( ) . ok_or_else ( wrong_args) ?. to_owned ( ) ;
119+ let hash_function_integer = from_value :: < u8 > ( arg) . map_err ( |_| wrong_args ( ) ) ?;
120+ let hash_function_code =
121+ RadonHashFunctions :: try_from ( hash_function_integer) . map_err ( |_| wrong_args ( ) ) ?;
122+
123+ let digest = hash_functions:: hash ( input_bytes, hash_function_code) ?;
124+ let hex_string = hex:: encode ( digest) ;
125+
126+ Ok ( RadonString :: from ( hex_string) )
127+ }
128+
23129/// Parse `RadonTypes` from a JSON-encoded `RadonString`.
24130pub fn parse_json ( input : & RadonString ) -> Result < RadonTypes , RadError > {
25131 let json_value: JsonValue =
@@ -142,6 +248,10 @@ pub fn parse_xml_map(input: &RadonString) -> Result<RadonMap, RadError> {
142248 }
143249}
144250
251+ pub fn length ( input : & RadonString ) -> RadonInteger {
252+ RadonInteger :: from ( input. value ( ) . len ( ) as i128 )
253+ }
254+
145255pub fn radon_trim ( input : & RadonString ) -> String {
146256 if input. value ( ) . ends_with ( '\n' ) {
147257 input. value ( ) [ ..input. value ( ) . len ( ) - 1 ] . to_string ( )
@@ -150,84 +260,10 @@ pub fn radon_trim(input: &RadonString) -> String {
150260 }
151261}
152262
153- pub fn to_bool ( input : & RadonString ) -> Result < RadonBoolean , RadError > {
154- let str_value = radon_trim ( input) ;
155- bool:: from_str ( & str_value)
156- . map ( RadonBoolean :: from)
157- . map_err ( Into :: into)
158- }
159-
160- /// Converts a `RadonString` into a `RadonFloat`, provided that the input string actually represents
161- /// a valid floating point number.
162- pub fn as_float ( input : & RadonString , args : & Option < Vec < Value > > ) -> Result < RadonFloat , RadError > {
163- f64:: from_str ( & as_numeric_string (
164- input,
165- args. as_deref ( ) . unwrap_or_default ( ) ,
166- ) )
167- . map ( RadonFloat :: from)
168- . map_err ( Into :: into)
169- }
170-
171- /// Converts a `RadonString` into a `RadonFloat`, provided that the input string actually represents
172- /// a valid integer number.
173- pub fn as_integer (
174- input : & RadonString ,
175- args : & Option < Vec < Value > > ,
176- ) -> Result < RadonInteger , RadError > {
177- i128:: from_str ( & as_numeric_string (
178- input,
179- args. as_deref ( ) . unwrap_or_default ( ) ,
180- ) )
181- . map ( RadonInteger :: from)
182- . map_err ( Into :: into)
183- }
184-
185- /// Converts a `RadonString` into a `String` containing a numeric value, provided that the input
186- /// string actually represents a valid number.
187- pub fn as_numeric_string ( input : & RadonString , args : & [ Value ] ) -> String {
188- let str_value = radon_trim ( input) ;
189- let ( thousands_separator, decimal_separator) = read_separators_from_args ( args) ;
190-
191- replace_separators ( str_value, thousands_separator, decimal_separator)
192- }
193-
194- pub fn length ( input : & RadonString ) -> RadonInteger {
195- RadonInteger :: from ( input. value ( ) . len ( ) as i128 )
196- }
197-
198- pub fn to_lowercase ( input : & RadonString ) -> RadonString {
199- RadonString :: from ( input. value ( ) . as_str ( ) . to_lowercase ( ) )
200- }
201-
202- pub fn to_uppercase ( input : & RadonString ) -> RadonString {
203- RadonString :: from ( input. value ( ) . as_str ( ) . to_uppercase ( ) )
204- }
205-
206- pub fn hash ( input : & RadonString , args : & [ Value ] ) -> Result < RadonString , RadError > {
207- let wrong_args = || RadError :: WrongArguments {
208- input_type : RadonString :: radon_type_name ( ) ,
209- operator : "Hash" . to_string ( ) ,
210- args : args. to_vec ( ) ,
211- } ;
212-
213- let input_string = input. value ( ) ;
214- let input_bytes = input_string. as_bytes ( ) ;
215-
216- let arg = args. first ( ) . ok_or_else ( wrong_args) ?. to_owned ( ) ;
217- let hash_function_integer = from_value :: < u8 > ( arg) . map_err ( |_| wrong_args ( ) ) ?;
218- let hash_function_code =
219- RadonHashFunctions :: try_from ( hash_function_integer) . map_err ( |_| wrong_args ( ) ) ?;
220-
221- let digest = hash_functions:: hash ( input_bytes, hash_function_code) ?;
222- let hex_string = hex:: encode ( digest) ;
223-
224- Ok ( RadonString :: from ( hex_string) )
225- }
226-
227263pub fn string_match ( input : & RadonString , args : & [ Value ] ) -> Result < RadonTypes , RadError > {
228264 let wrong_args = || RadError :: WrongArguments {
229265 input_type : RadonString :: radon_type_name ( ) ,
230- operator : "String match " . to_string ( ) ,
266+ operator : "StringMatch " . to_string ( ) ,
231267 args : args. to_vec ( ) ,
232268 } ;
233269
@@ -281,6 +317,66 @@ pub fn string_match(input: &RadonString, args: &[Value]) -> Result<RadonTypes, R
281317 . unwrap_or ( Ok ( temp_def) )
282318}
283319
320+ pub fn string_replace ( input : & RadonString , args : & [ Value ] ) -> Result < RadonString , RadError > {
321+ let wrong_args = || RadError :: WrongArguments {
322+ input_type : RadonString :: radon_type_name ( ) ,
323+ operator : "StringReplace" . to_string ( ) ,
324+ args : args. to_vec ( ) ,
325+ } ;
326+ let regex = RadonString :: try_from ( args. first ( ) . ok_or_else ( wrong_args) ?. to_owned ( ) ) ?;
327+ let replacement = RadonString :: try_from ( args. get ( 1 ) . ok_or_else ( wrong_args) ?. to_owned ( ) ) ?;
328+ Ok ( RadonString :: from ( input. value ( ) . as_str ( ) . replace (
329+ regex. value ( ) . as_str ( ) ,
330+ replacement. value ( ) . as_str ( ) ,
331+ ) ) )
332+ }
333+
334+ pub fn string_slice ( input : & RadonString , args : & [ Value ] ) -> Result < RadonString , RadError > {
335+ let wrong_args = || RadError :: WrongArguments {
336+ input_type : RadonString :: radon_type_name ( ) ,
337+ operator : "StringSlice" . to_string ( ) ,
338+ args : args. to_vec ( ) ,
339+ } ;
340+ let mut end_index: usize = input. value ( ) . len ( ) ;
341+ match args. len ( ) {
342+ 2 => {
343+ let start_index = from_value :: < i64 > ( args[ 0 ] . clone ( ) )
344+ . unwrap_or_default ( )
345+ . rem_euclid ( end_index as i64 ) as usize ;
346+ end_index = from_value :: < i64 > ( args[ 1 ] . clone ( ) )
347+ . unwrap_or_default ( )
348+ . rem_euclid ( end_index as i64 ) as usize ;
349+ Ok ( RadonString :: from (
350+ input. value ( ) . as_str ( ) . slice ( start_index..end_index) ,
351+ ) )
352+ }
353+ 1 => {
354+ let start_index = from_value :: < i64 > ( args[ 0 ] . clone ( ) )
355+ . unwrap_or_default ( )
356+ . rem_euclid ( end_index as i64 ) as usize ;
357+ Ok ( RadonString :: from (
358+ input. value ( ) . as_str ( ) . slice ( start_index..end_index) ,
359+ ) )
360+ }
361+ _ => Err ( wrong_args ( ) ) ,
362+ }
363+ }
364+
365+ pub fn string_split ( input : & RadonString , args : & [ Value ] ) -> Result < RadonArray , RadError > {
366+ let wrong_args = || RadError :: WrongArguments {
367+ input_type : RadonString :: radon_type_name ( ) ,
368+ operator : "StringSplit" . to_string ( ) ,
369+ args : args. to_vec ( ) ,
370+ } ;
371+ let pattern = RadonString :: try_from ( args. first ( ) . ok_or_else ( wrong_args) ?. to_owned ( ) ) ?;
372+ let parts: Vec < RadonTypes > = Regex :: new ( pattern. value ( ) . as_str ( ) )
373+ . unwrap ( )
374+ . split ( input. value ( ) . as_str ( ) )
375+ . map ( |part| RadonTypes :: from ( RadonString :: from ( part) ) )
376+ . collect ( ) ;
377+ Ok ( RadonArray :: from ( parts) )
378+ }
379+
284380/// Replace thousands and decimals separators in a `String`.
285381#[ inline]
286382pub fn replace_separators (
@@ -321,6 +417,23 @@ fn default_decimal_separator<T>(_: T) -> String {
321417 String :: from ( DEFAULT_DECIMAL_SEPARATOR )
322418}
323419
420+ pub fn to_lowercase ( input : & RadonString ) -> RadonString {
421+ RadonString :: from ( input. value ( ) . as_str ( ) . to_lowercase ( ) )
422+ }
423+
424+ /// Converts a `RadonString` into a `String` containing a numeric value, provided that the input
425+ /// string actually represents a valid number.
426+ pub fn to_numeric_string ( input : & RadonString , args : & [ Value ] ) -> String {
427+ let str_value = radon_trim ( input) ;
428+ let ( thousands_separator, decimal_separator) = read_separators_from_args ( args) ;
429+
430+ replace_separators ( str_value, thousands_separator, decimal_separator)
431+ }
432+
433+ pub fn to_uppercase ( input : & RadonString ) -> RadonString {
434+ RadonString :: from ( input. value ( ) . as_str ( ) . to_uppercase ( ) )
435+ }
436+
324437/// This module was introduced for encapsulating the interim legacy logic before WIP-0024 is
325438/// introduced, for the sake of maintainability.
326439///
@@ -731,7 +844,7 @@ mod tests {
731844 let rad_float = RadonBoolean :: from ( false ) ;
732845 let rad_string: RadonString = RadonString :: from ( "false" ) ;
733846
734- assert_eq ! ( to_bool ( & rad_string) . unwrap( ) , rad_float) ;
847+ assert_eq ! ( as_bool ( & rad_string) . unwrap( ) , rad_float) ;
735848 }
736849
737850 #[ test]
0 commit comments