rhai/packages/
string_basic.rs

1use super::iter_basic::CharsStream;
2use crate::plugin::*;
3use crate::{def_package, FnPtr, ImmutableString, SmartString, INT};
4use std::any::TypeId;
5use std::fmt::{Binary, LowerHex, Octal, Write};
6#[cfg(feature = "no_std")]
7use std::prelude::v1::*;
8
9#[cfg(not(feature = "no_index"))]
10use crate::Array;
11
12#[cfg(not(feature = "no_object"))]
13use crate::Map;
14
15/// Standard pretty-print function.
16///
17/// This function is called to convert any type into text format for display.
18pub const FUNC_TO_STRING: &str = "to_string";
19
20/// Standard debug-print function.
21///
22/// This function is called to convert any type into text format suitable for debugging.
23pub const FUNC_TO_DEBUG: &str = "to_debug";
24
25def_package! {
26    /// Package of basic string utilities (e.g. printing)
27    pub BasicStringPackage(lib) {
28        lib.set_standard_lib(true);
29
30        combine_with_exported_module!(lib, "print_debug", print_debug_functions);
31        combine_with_exported_module!(lib, "number_formatting", number_formatting);
32        combine_with_exported_module!(lib, "char", char_functions);
33
34        // Register characters iterator
35        lib.set_iterator::<CharsStream>();
36
37        lib.set_iter(TypeId::of::<ImmutableString>(), |value| Box::new(
38            CharsStream::new(value.cast::<ImmutableString>().as_str(), 0, INT::MAX).map(Into::into)
39        ));
40    }
41}
42
43/// Print a value using a named function.
44#[inline]
45pub fn print_with_func(
46    fn_name: &str,
47    ctx: &NativeCallContext,
48    value: &mut Dynamic,
49) -> ImmutableString {
50    match ctx.call_native_fn_raw(fn_name, true, &mut [value]) {
51        Ok(result) if result.is_string() => result.into_immutable_string().unwrap(),
52        Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
53        Err(_) => {
54            let mut buf = SmartString::new_const();
55            match fn_name {
56                FUNC_TO_DEBUG => write!(&mut buf, "{value:?}").unwrap(),
57                _ => write!(&mut buf, "{value}").unwrap(),
58            }
59            ctx.engine().map_type_name(&buf).into()
60        }
61    }
62}
63
64#[export_module]
65mod print_debug_functions {
66    /// Convert the value of the `item` into a string.
67    #[rhai_fn(name = "print", pure)]
68    pub fn print_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
69        print_with_func(FUNC_TO_STRING, &ctx, item)
70    }
71    /// Convert the value of the `item` into a string.
72    #[rhai_fn(name = "to_string", pure)]
73    pub fn to_string_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
74        let mut buf = SmartString::new_const();
75        write!(&mut buf, "{item}").unwrap();
76        ctx.engine().map_type_name(&buf).into()
77    }
78    /// Convert the value of the `item` into a string in debug format.
79    #[rhai_fn(name = "debug", pure)]
80    pub fn debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
81        print_with_func(FUNC_TO_DEBUG, &ctx, item)
82    }
83    /// Convert the value of the `item` into a string in debug format.
84    #[rhai_fn(name = "to_debug", pure)]
85    pub fn to_debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
86        let mut buf = SmartString::new_const();
87        write!(&mut buf, "{item:?}").unwrap();
88        ctx.engine().map_type_name(&buf).into()
89    }
90
91    /// Return the empty string.
92    #[rhai_fn(name = "print", name = "debug")]
93    pub fn print_empty_string(ctx: NativeCallContext) -> ImmutableString {
94        ctx.engine().const_empty_string()
95    }
96
97    /// Return the `string`.
98    #[rhai_fn(name = "print", name = "to_string")]
99    pub const fn print_string(string: ImmutableString) -> ImmutableString {
100        string
101    }
102    /// Convert the string into debug format.
103    #[rhai_fn(name = "debug", name = "to_debug")]
104    pub fn debug_string(string: &str) -> ImmutableString {
105        let mut buf = SmartString::new_const();
106        write!(&mut buf, "{string:?}").unwrap();
107        buf.into()
108    }
109
110    /// Return the character into a string.
111    #[rhai_fn(name = "print", name = "to_string")]
112    pub fn print_char(character: char) -> ImmutableString {
113        let mut buf = SmartString::new_const();
114        buf.push(character);
115        buf.into()
116    }
117    /// Convert the string into debug format.
118    #[rhai_fn(name = "debug", name = "to_debug")]
119    pub fn debug_char(character: char) -> ImmutableString {
120        let mut buf = SmartString::new_const();
121        buf.push(character);
122        buf.into()
123    }
124
125    /// Convert the function pointer into a string in debug format.
126    #[rhai_fn(name = "debug", name = "to_debug", pure)]
127    pub fn debug_fn_ptr(f: &mut FnPtr) -> ImmutableString {
128        let mut buf = SmartString::new_const();
129        write!(&mut buf, "{f}").unwrap();
130        buf.into()
131    }
132
133    /// Return the boolean value into a string.
134    #[rhai_fn(name = "print", name = "to_string")]
135    pub fn print_bool(value: bool) -> ImmutableString {
136        let mut buf = SmartString::new_const();
137        write!(&mut buf, "{value}").unwrap();
138        buf.into()
139    }
140    /// Convert the boolean value into a string in debug format.
141    #[rhai_fn(name = "debug", name = "to_debug")]
142    pub fn debug_bool(value: bool) -> ImmutableString {
143        let mut buf = SmartString::new_const();
144        write!(&mut buf, "{value:?}").unwrap();
145        buf.into()
146    }
147
148    /// Return the empty string.
149    #[allow(unused_variables)]
150    #[rhai_fn(name = "print", name = "to_string")]
151    pub fn print_unit(ctx: NativeCallContext, unit: ()) -> ImmutableString {
152        ctx.engine().const_empty_string()
153    }
154    /// Convert the unit into a string in debug format.
155    #[allow(unused_variables)]
156    #[rhai_fn(name = "debug", name = "to_debug")]
157    pub fn debug_unit(unit: ()) -> ImmutableString {
158        "()".into()
159    }
160
161    /// Convert the value of `number` into a string.
162    #[cfg(not(feature = "no_float"))]
163    #[rhai_fn(name = "print", name = "to_string")]
164    pub fn print_f64(number: f64) -> ImmutableString {
165        let mut buf = SmartString::new_const();
166        write!(&mut buf, "{}", crate::types::FloatWrapper::new(number)).unwrap();
167        buf.into()
168    }
169    /// Convert the value of `number` into a string.
170    #[cfg(not(feature = "no_float"))]
171    #[rhai_fn(name = "print", name = "to_string")]
172    pub fn print_f32(number: f32) -> ImmutableString {
173        let mut buf = SmartString::new_const();
174        write!(&mut buf, "{}", crate::types::FloatWrapper::new(number)).unwrap();
175        buf.into()
176    }
177    /// Convert the value of `number` into a string.
178    #[cfg(not(feature = "no_float"))]
179    #[rhai_fn(name = "debug", name = "to_debug")]
180    pub fn debug_f64(number: f64) -> ImmutableString {
181        let mut buf = SmartString::new_const();
182        write!(&mut buf, "{:?}", crate::types::FloatWrapper::new(number)).unwrap();
183        buf.into()
184    }
185    /// Convert the value of `number` into a string.
186    #[cfg(not(feature = "no_float"))]
187    #[rhai_fn(name = "debug", name = "to_debug")]
188    pub fn debug_f32(number: f32) -> ImmutableString {
189        let mut buf = SmartString::new_const();
190        write!(&mut buf, "{:?}", crate::types::FloatWrapper::new(number)).unwrap();
191        buf.into()
192    }
193
194    /// Convert the array into a string.
195    #[cfg(not(feature = "no_index"))]
196    #[rhai_fn(
197        name = "print",
198        name = "to_string",
199        name = "debug",
200        name = "to_debug",
201        pure
202    )]
203    pub fn format_array(ctx: NativeCallContext, array: &mut Array) -> ImmutableString {
204        let len = array.len();
205        let mut result = SmartString::new_const();
206        result.push_str("[");
207
208        array.iter_mut().enumerate().for_each(|(i, x)| {
209            result.push_str(&print_with_func(FUNC_TO_DEBUG, &ctx, x));
210            if i < len - 1 {
211                result.push_str(", ");
212            }
213        });
214
215        result.push_str("]");
216        result.into()
217    }
218
219    /// Convert the object map into a string.
220    #[cfg(not(feature = "no_object"))]
221    #[rhai_fn(
222        name = "print",
223        name = "to_string",
224        name = "debug",
225        name = "to_debug",
226        pure
227    )]
228    pub fn format_map(ctx: NativeCallContext, map: &mut Map) -> ImmutableString {
229        let len = map.len();
230        let mut result = SmartString::new_const();
231        result.push_str("#{");
232
233        map.iter_mut().enumerate().for_each(|(i, (k, v))| {
234            write!(
235                result,
236                "{:?}: {}{}",
237                k,
238                &print_with_func(FUNC_TO_DEBUG, &ctx, v),
239                if i < len - 1 { ", " } else { "" }
240            )
241            .unwrap();
242        });
243
244        result.push_str("}");
245        result.into()
246    }
247}
248
249#[export_module]
250mod number_formatting {
251    fn to_hex<T: LowerHex>(value: T) -> ImmutableString {
252        let mut buf = SmartString::new_const();
253        write!(&mut buf, "{value:x}").unwrap();
254        buf.into()
255    }
256    fn to_octal<T: Octal>(value: T) -> ImmutableString {
257        let mut buf = SmartString::new_const();
258        write!(&mut buf, "{value:o}").unwrap();
259        buf.into()
260    }
261    fn to_binary<T: Binary>(value: T) -> ImmutableString {
262        let mut buf = SmartString::new_const();
263        write!(&mut buf, "{value:b}").unwrap();
264        buf.into()
265    }
266
267    /// Convert the `value` into a string in hex format.
268    #[rhai_fn(name = "to_hex")]
269    pub fn int_to_hex(value: INT) -> ImmutableString {
270        to_hex(value)
271    }
272    /// Convert the `value` into a string in octal format.
273    #[rhai_fn(name = "to_octal")]
274    pub fn int_to_octal(value: INT) -> ImmutableString {
275        to_octal(value)
276    }
277    /// Convert the `value` into a string in binary format.
278    #[rhai_fn(name = "to_binary")]
279    pub fn int_to_binary(value: INT) -> ImmutableString {
280        to_binary(value)
281    }
282
283    #[cfg(not(feature = "only_i32"))]
284    #[cfg(not(feature = "only_i64"))]
285    pub mod numbers {
286        /// Convert the `value` into a string in hex format.
287        #[rhai_fn(name = "to_hex")]
288        pub fn u8_to_hex(value: u8) -> ImmutableString {
289            to_hex(value)
290        }
291        /// Convert the `value` into a string in hex format.
292        #[rhai_fn(name = "to_hex")]
293        pub fn u16_to_hex(value: u16) -> ImmutableString {
294            to_hex(value)
295        }
296        /// Convert the `value` into a string in hex format.
297        #[rhai_fn(name = "to_hex")]
298        pub fn u32_to_hex(value: u32) -> ImmutableString {
299            to_hex(value)
300        }
301        /// Convert the `value` into a string in hex format.
302        #[rhai_fn(name = "to_hex")]
303        pub fn u64_to_hex(value: u64) -> ImmutableString {
304            to_hex(value)
305        }
306        /// Convert the `value` into a string in hex format.
307        #[rhai_fn(name = "to_hex")]
308        pub fn i8_to_hex(value: i8) -> ImmutableString {
309            to_hex(value)
310        }
311        /// Convert the `value` into a string in hex format.
312        #[rhai_fn(name = "to_hex")]
313        pub fn i16_to_hex(value: i16) -> ImmutableString {
314            to_hex(value)
315        }
316        /// Convert the `value` into a string in hex format.
317        #[rhai_fn(name = "to_hex")]
318        pub fn i32_to_hex(value: i32) -> ImmutableString {
319            to_hex(value)
320        }
321        /// Convert the `value` into a string in hex format.
322        #[rhai_fn(name = "to_hex")]
323        pub fn i64_to_hex(value: i64) -> ImmutableString {
324            to_hex(value)
325        }
326        /// Convert the `value` into a string in octal format.
327        #[rhai_fn(name = "to_octal")]
328        pub fn u8_to_octal(value: u8) -> ImmutableString {
329            to_octal(value)
330        }
331        /// Convert the `value` into a string in octal format.
332        #[rhai_fn(name = "to_octal")]
333        pub fn u16_to_octal(value: u16) -> ImmutableString {
334            to_octal(value)
335        }
336        /// Convert the `value` into a string in octal format.
337        #[rhai_fn(name = "to_octal")]
338        pub fn u32_to_octal(value: u32) -> ImmutableString {
339            to_octal(value)
340        }
341        /// Convert the `value` into a string in octal format.
342        #[rhai_fn(name = "to_octal")]
343        pub fn u64_to_octal(value: u64) -> ImmutableString {
344            to_octal(value)
345        }
346        /// Convert the `value` into a string in octal format.
347        #[rhai_fn(name = "to_octal")]
348        pub fn i8_to_octal(value: i8) -> ImmutableString {
349            to_octal(value)
350        }
351        /// Convert the `value` into a string in octal format.
352        #[rhai_fn(name = "to_octal")]
353        pub fn i16_to_octal(value: i16) -> ImmutableString {
354            to_octal(value)
355        }
356        /// Convert the `value` into a string in octal format.
357        #[rhai_fn(name = "to_octal")]
358        pub fn i32_to_octal(value: i32) -> ImmutableString {
359            to_octal(value)
360        }
361        /// Convert the `value` into a string in octal format.
362        #[rhai_fn(name = "to_octal")]
363        pub fn i64_to_octal(value: i64) -> ImmutableString {
364            to_octal(value)
365        }
366        /// Convert the `value` into a string in binary format.
367        #[rhai_fn(name = "to_binary")]
368        pub fn u8_to_binary(value: u8) -> ImmutableString {
369            to_binary(value)
370        }
371        /// Convert the `value` into a string in binary format.
372        #[rhai_fn(name = "to_binary")]
373        pub fn u16_to_binary(value: u16) -> ImmutableString {
374            to_binary(value)
375        }
376        /// Convert the `value` into a string in binary format.
377        #[rhai_fn(name = "to_binary")]
378        pub fn u32_to_binary(value: u32) -> ImmutableString {
379            to_binary(value)
380        }
381        /// Convert the `value` into a string in binary format.
382        #[rhai_fn(name = "to_binary")]
383        pub fn u64_to_binary(value: u64) -> ImmutableString {
384            to_binary(value)
385        }
386        /// Convert the `value` into a string in binary format.
387        #[rhai_fn(name = "to_binary")]
388        pub fn i8_to_binary(value: i8) -> ImmutableString {
389            to_binary(value)
390        }
391        /// Convert the `value` into a string in binary format.
392        #[rhai_fn(name = "to_binary")]
393        pub fn i16_to_binary(value: i16) -> ImmutableString {
394            to_binary(value)
395        }
396        /// Convert the `value` into a string in binary format.
397        #[rhai_fn(name = "to_binary")]
398        pub fn i32_to_binary(value: i32) -> ImmutableString {
399            to_binary(value)
400        }
401        /// Convert the `value` into a string in binary format.
402        #[rhai_fn(name = "to_binary")]
403        pub fn i64_to_binary(value: i64) -> ImmutableString {
404            to_binary(value)
405        }
406
407        #[cfg(not(target_family = "wasm"))]
408        pub mod num_128 {
409            /// Convert the `value` into a string in hex format.
410            #[rhai_fn(name = "to_hex")]
411            pub fn u128_to_hex(value: u128) -> ImmutableString {
412                to_hex(value)
413            }
414            /// Convert the `value` into a string in hex format.
415            #[rhai_fn(name = "to_hex")]
416            pub fn i128_to_hex(value: i128) -> ImmutableString {
417                to_hex(value)
418            }
419            /// Convert the `value` into a string in octal format.
420            #[rhai_fn(name = "to_octal")]
421            pub fn u128_to_octal(value: u128) -> ImmutableString {
422                to_octal(value)
423            }
424            /// Convert the `value` into a string in octal format.
425            #[rhai_fn(name = "to_octal")]
426            pub fn i128_to_octal(value: i128) -> ImmutableString {
427                to_octal(value)
428            }
429            /// Convert the `value` into a string in binary format.
430            #[rhai_fn(name = "to_binary")]
431            pub fn u128_to_binary(value: u128) -> ImmutableString {
432                to_binary(value)
433            }
434            /// Convert the `value` into a string in binary format.
435            #[rhai_fn(name = "to_binary")]
436            pub fn i128_to_binary(value: i128) -> ImmutableString {
437                to_binary(value)
438            }
439        }
440    }
441}
442
443#[export_module]
444mod char_functions {
445    /// Convert the Unicode character into a 32-bit integer value.
446    pub const fn to_int(ch: char) -> INT {
447        (ch as u32) as INT
448    }
449}