mtots/mds/
regex.rs

1use crate::mtry;
2use crate::ArgSpec;
3use crate::NativeModule;
4use crate::RcStr;
5use crate::Value;
6use regex::Regex;
7
8pub const NAME: &str = "a.regex";
9
10pub(super) fn new() -> NativeModule {
11    NativeModule::new(NAME, |m| {
12        m.class::<Regex, _>("Regex", |cls| {
13            cls.doc("Binding to Rust/Cargo's 'regex' crate");
14            cls.sfunc("__call", ["pattern"], "", |globals, args, _| {
15                let mut args = args.into_iter();
16                let pattern = args.next().unwrap().into_string()?;
17                let re = mtry!(Regex::new(&pattern));
18                globals.new_handle::<Regex>(re).map(From::from)
19            });
20            cls.ifunc(
21                "find",
22                ArgSpec::builder()
23                    .req("text")
24                    .def("start", ())
25                    .def("end", ()),
26                "",
27                |owner, globals, args, _| {
28                    let mut args = args.into_iter();
29                    let text = args.next().unwrap().into_string()?;
30                    let len = text.len();
31                    let start = args.next().unwrap().to_start_index(len)?;
32                    let end = args.next().unwrap().to_end_index(len)?;
33                    let match_ = owner.borrow().find(&text[start..end]);
34                    Ok(match match_ {
35                        Some(match_) => globals
36                            .new_handle(OwnedMatch {
37                                text: text.clone(),
38                                start: start + match_.start(),
39                                end: start + match_.end(),
40                            })?
41                            .into(),
42                        None => Value::Nil,
43                    })
44                },
45            );
46            cls.ifunc(
47                "replace",
48                ["text", "replacement"],
49                "",
50                |owner, _globals, args, _| {
51                    let mut args = args.into_iter();
52                    let text = args.next().unwrap().into_string()?;
53                    let replacement = args.next().unwrap().into_string()?;
54                    Ok(owner
55                        .borrow()
56                        .replace(&text, replacement.str())
57                        .into_owned()
58                        .into())
59                },
60            );
61        });
62        m.class::<OwnedMatch, _>("Match", |cls| {
63            cls.str(|match_| match_.str().into());
64            cls.repr(|match_| format!("Match({:?})", match_.str()).into());
65            cls.ifunc("start", (), "", |owner, _, _, _| {
66                Ok(owner.borrow().start.into())
67            });
68            cls.ifunc("end", (), "", |owner, _, _, _| {
69                Ok(owner.borrow().end.into())
70            });
71            cls.ifunc("str", (), "", |owner, _, _, _| {
72                Ok(owner.borrow().str().into())
73            });
74        });
75    })
76}
77
78pub struct OwnedMatch {
79    text: RcStr,
80    start: usize,
81    end: usize,
82}
83
84impl OwnedMatch {
85    pub fn str(&self) -> &str {
86        &self.text[self.start..self.end]
87    }
88}