1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use std::mem;
use crate::convert::{FromMrb, RustBackedValue};
use crate::extn::core::regexp::{syntax, Regexp};
use crate::sys;
use crate::value::types::Ruby;
use crate::value::{Value, ValueLike};
use crate::Mrb;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum Error {
Fatal,
NoImplicitConversionToString,
}
#[derive(Debug)]
pub struct Args {
pub rest: Vec<Value>,
}
impl Args {
const ARGSPEC: &'static [u8] = b"*\0";
pub unsafe fn extract(interp: &Mrb) -> Self {
let mut args = <mem::MaybeUninit<*const sys::mrb_value>>::uninit();
let mut count = <mem::MaybeUninit<usize>>::uninit();
sys::mrb_get_args(
interp.borrow().mrb,
Self::ARGSPEC.as_ptr() as *const i8,
args.as_mut_ptr(),
count.as_mut_ptr(),
);
let args = std::slice::from_raw_parts(args.assume_init(), count.assume_init());
let args = args
.iter()
.map(|value| Value::new(&interp, *value))
.collect::<Vec<_>>();
Self { rest: args }
}
}
pub fn method(interp: &Mrb, args: Args, slf: sys::mrb_value) -> Result<Value, Error> {
let mrb = interp.borrow().mrb;
let pattern = if args.rest.is_empty() {
"(?!)".to_owned()
} else if args.rest.len() == 1 {
let arg = args.rest.into_iter().nth(0).unwrap();
if arg.ruby_type() == Ruby::Array {
let mut patterns = vec![];
for pattern in arg
.itself::<Vec<Value>>()
.map_err(|_| Error::NoImplicitConversionToString)?
{
if let Ok(regexp) = unsafe { Regexp::try_from_ruby(&interp, &pattern) } {
patterns.push(regexp.borrow().pattern.clone());
} else if let Ok(pattern) = pattern.funcall::<String, _, _>("to_str", &[]) {
patterns.push(syntax::escape(pattern.as_str()));
} else {
return Err(Error::NoImplicitConversionToString);
}
}
patterns.join("|")
} else {
let pattern = arg;
if let Ok(regexp) = unsafe { Regexp::try_from_ruby(&interp, &pattern) } {
regexp.borrow().pattern.clone()
} else if let Ok(pattern) = pattern.funcall::<String, _, _>("to_str", &[]) {
syntax::escape(pattern.as_str())
} else {
return Err(Error::NoImplicitConversionToString);
}
}
} else {
let mut patterns = vec![];
for pattern in args.rest {
if let Ok(regexp) = unsafe { Regexp::try_from_ruby(&interp, &pattern) } {
patterns.push(regexp.borrow().pattern.clone());
} else if let Ok(pattern) = pattern.funcall::<String, _, _>("to_str", &[]) {
patterns.push(syntax::escape(pattern.as_str()));
} else {
return Err(Error::NoImplicitConversionToString);
}
}
patterns.join("|")
};
let value = unsafe {
sys::mrb_obj_new(
mrb,
sys::mrb_sys_class_ptr(slf),
1,
[Value::from_mrb(interp, pattern).inner()].as_ptr() as *const sys::mrb_value,
)
};
Ok(Value::new(interp, value))
}