artichoke_backend/extn/core/regexp/
trampoline.rs
1use crate::convert::{implicitly_convert_to_int, implicitly_convert_to_nilable_string, implicitly_convert_to_string};
2use crate::extn::core::regexp::Regexp;
3use crate::extn::core::symbol::Symbol;
4use crate::extn::prelude::*;
5
6pub fn initialize(
7 interp: &mut Artichoke,
8 pattern: Value,
9 options: Option<Value>,
10 encoding: Option<Value>,
11 mut into: Value,
12) -> Result<Value, Error> {
13 if let Ok(existing) = unsafe { Regexp::unbox_from_value(&mut into, interp) } {
14 if existing.is_literal() {
15 return Err(FrozenError::with_message("can't modify literal regexp").into());
16 }
17 return Err(TypeError::with_message("already initialized regexp").into());
18 }
19 let (options, encoding) = interp.try_convert_mut((options, encoding))?;
20 let regexp = Regexp::initialize(interp, pattern, options, encoding)?;
21 let mut value = Regexp::box_into_value(regexp, into, interp)?;
22 if matches!(options, Some(options) if options.is_literal()) {
23 value.freeze(interp)?;
24 }
25 Ok(value)
26}
27
28pub fn escape(interp: &mut Artichoke, mut pattern: Value) -> Result<Value, Error> {
29 let pattern_vec = if let Ruby::Symbol = pattern.ruby_type() {
30 let symbol = unsafe { Symbol::unbox_from_value(&mut pattern, interp)? };
31 symbol.bytes(interp).to_vec()
32 } else {
33 unsafe { implicitly_convert_to_string(interp, &mut pattern)?.to_vec() }
37 };
38 let pattern = Regexp::escape(&pattern_vec)?;
39 interp.try_convert_mut(pattern)
40}
41
42pub fn union<T>(interp: &mut Artichoke, patterns: T) -> Result<Value, Error>
43where
44 T: IntoIterator<Item = Value>,
45{
46 let regexp = Regexp::union(interp, patterns)?;
47 Regexp::alloc_value(regexp, interp)
48}
49
50pub fn is_match(
51 interp: &mut Artichoke,
52 mut regexp: Value,
53 mut pattern: Value,
54 pos: Option<Value>,
55) -> Result<Value, Error> {
56 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
57 let pattern = unsafe { implicitly_convert_to_nilable_string(interp, &mut pattern)? };
58 let pos = if let Some(pos) = pos {
59 Some(implicitly_convert_to_int(interp, pos)?)
60 } else {
61 None
62 };
63 let is_match = regexp.is_match(pattern, pos)?;
64 Ok(interp.convert(is_match))
65}
66
67pub fn match_(
68 interp: &mut Artichoke,
69 mut regexp: Value,
70 mut pattern: Value,
71 pos: Option<Value>,
72 block: Option<Block>,
73) -> Result<Value, Error> {
74 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
75 let pattern_vec;
76 let pattern = if let Ruby::Symbol = pattern.ruby_type() {
77 let symbol = unsafe { Symbol::unbox_from_value(&mut pattern, interp)? };
78 pattern_vec = symbol.bytes(interp).to_vec();
79 Some(pattern_vec.as_slice())
80 } else {
81 unsafe { implicitly_convert_to_nilable_string(interp, &mut pattern)? }
82 };
83 let pos = if let Some(pos) = pos {
84 Some(implicitly_convert_to_int(interp, pos)?)
85 } else {
86 None
87 };
88 regexp.match_(interp, pattern, pos, block)
89}
90
91pub fn eql(interp: &mut Artichoke, mut regexp: Value, other: Value) -> Result<Value, Error> {
92 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
93 let cmp = regexp.eql(interp, other);
94 Ok(interp.convert(cmp))
95}
96
97pub fn case_compare(interp: &mut Artichoke, mut regexp: Value, other: Value) -> Result<Value, Error> {
98 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
99 let cmp = regexp.case_compare(interp, other)?;
100 Ok(interp.convert(cmp))
101}
102
103pub fn match_operator(interp: &mut Artichoke, mut regexp: Value, mut pattern: Value) -> Result<Value, Error> {
104 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
105 let pattern_vec;
106 let pattern = if let Ruby::Symbol = pattern.ruby_type() {
107 let symbol = unsafe { Symbol::unbox_from_value(&mut pattern, interp)? };
108 pattern_vec = symbol.bytes(interp).to_vec();
109 Some(pattern_vec.as_slice())
110 } else {
111 unsafe { implicitly_convert_to_nilable_string(interp, &mut pattern)? }
112 };
113 let pos = regexp.match_operator(interp, pattern)?;
114 match pos.map(i64::try_from) {
115 Some(Ok(pos)) => Ok(interp.convert(pos)),
116 Some(Err(_)) => Err(ArgumentError::with_message("string too long").into()),
117 None => Ok(Value::nil()),
118 }
119}
120
121pub fn is_casefold(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
122 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
123 let is_casefold = regexp.is_casefold();
124 Ok(interp.convert(is_casefold))
125}
126
127pub fn is_fixed_encoding(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
128 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
129 let is_fixed_encoding = regexp.is_fixed_encoding();
130 Ok(interp.convert(is_fixed_encoding))
131}
132
133pub fn hash(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
134 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
135 let hash = regexp.hash();
136 let hash = i64::from_ne_bytes(hash.to_ne_bytes());
139 Ok(interp.convert(hash))
140}
141
142pub fn inspect(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
143 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
144 let inspect = regexp.inspect();
145 interp.try_convert_mut(inspect)
146}
147
148pub fn named_captures(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
149 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
150 let named_captures = regexp.named_captures()?;
151 interp.try_convert_mut(named_captures)
152}
153
154pub fn names(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
155 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
156 let names = regexp.names();
157 interp.try_convert_mut(names)
158}
159
160pub fn options(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
161 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
162 let opts = regexp.options();
163 Ok(interp.convert(opts))
164}
165
166pub fn source(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
167 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
168 let source = regexp.source();
169 interp.try_convert_mut(source)
170}
171
172pub fn to_s(interp: &mut Artichoke, mut regexp: Value) -> Result<Value, Error> {
173 let regexp = unsafe { Regexp::unbox_from_value(&mut regexp, interp)? };
174 let s = regexp.string();
175 interp.try_convert_mut(s)
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use crate::test::prelude::*;
182
183 #[test]
184 fn should_raise_frozen_error() {
185 let mut interp = interpreter();
186 let pattern = interp.try_convert_mut("xyz").unwrap();
187 let options = None;
188 let encoding = None;
189 let slf = interp.eval(b"/abc/").unwrap();
190 let result = initialize(&mut interp, pattern, options, encoding, slf);
191 assert_eq!(
192 "FrozenError (can't modify literal regexp)",
193 result.unwrap_err().to_string()
194 );
195 }
196}