intuicio_frontend_simpleton/library/
text.rs

1use crate::{Array, Boolean, Integer, Reference, Text};
2use intuicio_core::{define_native_struct, registry::Registry};
3use intuicio_derive::intuicio_function;
4use regex::{Captures, Regex};
5
6use super::bytes::Bytes;
7
8thread_local! {
9    static FORMAT_REGEX: Regex = Regex::new(r#"\{(\d+)\}"#).unwrap();
10}
11
12#[intuicio_function(module_name = "text", use_registry)]
13pub fn length(registry: &Registry, text: Reference) -> Reference {
14    Reference::new_integer(text.read::<Text>().unwrap().len() as Integer, registry)
15}
16
17#[intuicio_function(module_name = "text", use_registry)]
18pub fn character(registry: &Registry, text: Reference, index: Reference) -> Reference {
19    let index = *index.read::<Integer>().unwrap() as usize;
20    text.read::<Text>()
21        .unwrap()
22        .chars()
23        .nth(index)
24        .map(|character| Reference::new_text(Text::from(character), registry))
25        .unwrap_or_default()
26}
27
28#[intuicio_function(module_name = "text", use_registry)]
29pub fn find(
30    registry: &Registry,
31    text: Reference,
32    pattern: Reference,
33    reverse: Reference,
34) -> Reference {
35    if *reverse.read::<Boolean>().unwrap() {
36        text.read::<Text>()
37            .unwrap()
38            .rfind(pattern.read::<Text>().unwrap().as_str())
39            .map(|index| Reference::new_integer(index as Integer, registry))
40            .unwrap_or(Reference::new_integer(-1, registry))
41    } else {
42        text.read::<Text>()
43            .unwrap()
44            .find(pattern.read::<Text>().unwrap().as_str())
45            .map(|index| Reference::new_integer(index as Integer, registry))
46            .unwrap_or(Reference::new_integer(-1, registry))
47    }
48}
49
50#[intuicio_function(module_name = "text", use_registry)]
51pub fn slice(
52    registry: &Registry,
53    text: Reference,
54    index: Reference,
55    count: Reference,
56) -> Reference {
57    let index = *index.read::<Integer>().unwrap() as usize;
58    let count = *count.read::<Integer>().unwrap() as usize;
59    Reference::new_text(
60        text.read::<Text>()
61            .unwrap()
62            .chars()
63            .skip(index)
64            .take(count)
65            .collect::<Text>(),
66        registry,
67    )
68}
69
70#[intuicio_function(module_name = "text", use_registry)]
71pub fn join(registry: &Registry, array: Reference, separator: Reference) -> Reference {
72    Reference::new_text(
73        array
74            .read::<Array>()
75            .unwrap()
76            .iter()
77            .map(|item| item.read::<Text>().unwrap().to_owned())
78            .collect::<Vec<_>>()
79            .join(separator.read::<Text>().unwrap().as_str()),
80        registry,
81    )
82}
83
84#[intuicio_function(module_name = "text", use_registry)]
85pub fn combine(registry: &Registry, a: Reference, b: Reference) -> Reference {
86    Reference::new_text(
87        a.read::<Text>().unwrap().to_owned() + b.read::<Text>().unwrap().as_str(),
88        registry,
89    )
90}
91
92#[intuicio_function(module_name = "text", use_registry)]
93pub fn format(registry: &Registry, template: Reference, arguments: Reference) -> Reference {
94    let arguments = &*arguments.read::<Array>().unwrap();
95    let result = FORMAT_REGEX.with(|regex| {
96        regex
97            .replace_all(
98                template.read::<Text>().unwrap().as_str(),
99                |captures: &Captures| {
100                    let capture = &captures[1];
101                    capture
102                        .parse::<usize>()
103                        .map(|index| arguments[index].read::<Text>().unwrap().to_owned())
104                        .unwrap_or_else(|_| capture.to_owned())
105                },
106            )
107            .as_ref()
108            .to_owned()
109    });
110    Reference::new_text(result, registry)
111}
112
113#[intuicio_function(module_name = "text", use_registry)]
114pub fn split(registry: &Registry, value: Reference, separator: Reference) -> Reference {
115    let result = value
116        .read::<Text>()
117        .unwrap()
118        .split(separator.read::<Text>().unwrap().as_str())
119        .filter(|part| !part.is_empty())
120        .map(|part| Reference::new_text(part.to_owned(), registry))
121        .collect::<Array>();
122    Reference::new_array(result, registry)
123}
124
125#[intuicio_function(module_name = "text", use_registry)]
126pub fn to_bytes(registry: &Registry, value: Reference) -> Reference {
127    let result = value.read::<Text>().unwrap().as_bytes().to_owned();
128    Reference::new(Bytes::new_raw(result), registry)
129}
130
131#[intuicio_function(module_name = "text", use_registry)]
132pub fn from_bytes(registry: &Registry, bytes: Reference) -> Reference {
133    let result = bytes.read::<Bytes>().unwrap();
134    Reference::new_text(
135        String::from_utf8_lossy(result.get_ref()).to_string(),
136        registry,
137    )
138}
139
140#[intuicio_function(module_name = "text", use_registry)]
141pub fn equals(registry: &Registry, a: Reference, b: Reference) -> Reference {
142    if let (Some(a), Some(b)) = (a.read::<Text>(), b.read::<Text>()) {
143        return Reference::new_boolean(*a == *b, registry);
144    }
145    Reference::null()
146}
147
148#[intuicio_function(module_name = "text", use_registry)]
149pub fn not_equals(registry: &Registry, a: Reference, b: Reference) -> Reference {
150    if let (Some(a), Some(b)) = (a.read::<Text>(), b.read::<Text>()) {
151        return Reference::new_boolean(*a != *b, registry);
152    }
153    Reference::null()
154}
155
156pub fn install(registry: &mut Registry) {
157    registry.add_type(define_native_struct! {
158        registry => mod text struct Text (Text) {}
159    });
160    registry.add_function(length::define_function(registry));
161    registry.add_function(character::define_function(registry));
162    registry.add_function(find::define_function(registry));
163    registry.add_function(slice::define_function(registry));
164    registry.add_function(join::define_function(registry));
165    registry.add_function(combine::define_function(registry));
166    registry.add_function(format::define_function(registry));
167    registry.add_function(split::define_function(registry));
168    registry.add_function(to_bytes::define_function(registry));
169    registry.add_function(from_bytes::define_function(registry));
170    registry.add_function(equals::define_function(registry));
171    registry.add_function(not_equals::define_function(registry));
172}