tantiny 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/helpers.rs CHANGED
@@ -1,202 +1,82 @@
1
+ use magnus::{r_hash::ForEach, Error, RArray, RHash, Ruby, TryConvert, Value};
1
2
  use std::collections::HashMap;
2
- use rutie::{AnyException, Array, Exception, RString, Hash, Integer, Float, Boolean, Module};
3
- use tantivy::tokenizer::Language;
4
-
5
- // Macro dependencies:
6
- pub(super) use paste::paste;
7
- pub(super) use rutie::{class, wrappable_struct, AnyObject, VerifiedObject, VM, Object, Class};
8
-
9
- pub(crate) fn namespace() -> Module {
10
- Module::from_existing("Tantiny")
11
- }
12
-
13
- pub(crate) struct LanguageWrapper(pub(crate) Language);
14
-
15
- impl std::str::FromStr for LanguageWrapper {
16
- type Err = String;
17
-
18
- fn from_str(s: &str) -> Result<Self, Self::Err> {
19
- match s {
20
- "en" => Ok(LanguageWrapper(Language::English)),
21
- "ar" => Ok(LanguageWrapper(Language::Arabic)),
22
- "da" => Ok(LanguageWrapper(Language::Danish)),
23
- "nl" => Ok(LanguageWrapper(Language::Dutch)),
24
- "fi" => Ok(LanguageWrapper(Language::Finnish)),
25
- "fr" => Ok(LanguageWrapper(Language::French)),
26
- "de" => Ok(LanguageWrapper(Language::German)),
27
- "el" => Ok(LanguageWrapper(Language::Greek)),
28
- "hu" => Ok(LanguageWrapper(Language::Hungarian)),
29
- "it" => Ok(LanguageWrapper(Language::Italian)),
30
- "no" => Ok(LanguageWrapper(Language::Norwegian)),
31
- "pt" => Ok(LanguageWrapper(Language::Portuguese)),
32
- "ro" => Ok(LanguageWrapper(Language::Romanian)),
33
- "ru" => Ok(LanguageWrapper(Language::Russian)),
34
- "es" => Ok(LanguageWrapper(Language::Spanish)),
35
- "sv" => Ok(LanguageWrapper(Language::Swedish)),
36
- "ta" => Ok(LanguageWrapper(Language::Tamil)),
37
- "tr" => Ok(LanguageWrapper(Language::Turkish)),
38
- _ => Err(format!("Language '{}' is not supported.", s)),
39
- }
40
- }
41
- }
42
-
43
- pub(crate) trait TryUnwrap<T> {
44
- fn try_unwrap(self) -> T;
45
- }
46
-
47
- macro_rules! primitive_try_unwrap_impl {
48
- ( $ruby_type:ty, $type:ty ) => {
49
- paste! {
50
- impl TryUnwrap<$type> for $ruby_type {
51
- fn try_unwrap(self) -> $type {
52
- self.[<to_ $type:lower>]()
53
- }
54
- }
55
-
56
- impl TryUnwrap<$type> for AnyObject {
57
- fn try_unwrap(self) -> $type {
58
- self.try_convert_to::<$ruby_type>()
59
- .try_unwrap()
60
- .[<to_ $type:lower>]()
61
- }
62
- }
63
- }
64
- };
65
- }
66
-
67
- primitive_try_unwrap_impl!(RString, String);
68
- primitive_try_unwrap_impl!(Integer, i64);
69
- primitive_try_unwrap_impl!(Float, f64);
70
- primitive_try_unwrap_impl!(Boolean, bool);
71
-
72
- impl<T> TryUnwrap<Vec<T>> for Array where
73
- AnyObject: TryUnwrap<T>
74
- {
75
- fn try_unwrap(self) -> Vec<T> {
76
- let mut vec = Vec::new();
77
-
78
- for elem in self {
79
- vec.push(elem.try_unwrap());
80
- }
81
-
82
- vec
83
- }
84
- }
85
-
86
- impl<K, V> TryUnwrap<HashMap<K, V>> for Hash where
87
- AnyObject: TryUnwrap<K> + TryUnwrap<V>,
88
- K: Eq + std::hash::Hash
89
- {
90
- fn try_unwrap(self) -> HashMap<K, V> {
91
- let mut hashmap = HashMap::new();
92
3
 
93
- self.each(|key, value| {
94
- hashmap.insert(key.try_unwrap(), value.try_unwrap());
95
- });
96
-
97
- hashmap
98
- }
99
- }
100
-
101
- impl<T, E> TryUnwrap<T> for Result<T, E>
4
+ /// Converts a Ruby hash to a HashMap where values can be either single values or arrays
5
+ pub fn hash_to_multivalue_map<K, V>(hash: RHash) -> Result<HashMap<K, Vec<V>>, Error>
102
6
  where
103
- E: ToString,
7
+ K: std::cmp::Eq + std::hash::Hash + TryConvert,
8
+ V: TryConvert,
104
9
  {
105
- fn try_unwrap(self) -> T {
106
- self.map_err(|e| {
107
- VM::raise_ex(AnyException::new(
108
- "Tantiny::TantivyError",
109
- Some(&e.to_string()),
110
- ))
111
- })
112
- .unwrap()
113
- }
114
- }
115
-
116
- impl<T> TryUnwrap<T> for Option<T> {
117
- fn try_unwrap(self) -> T {
118
- if let Some(value) = self {
119
- value
10
+ let ruby = unsafe { Ruby::get_unchecked() };
11
+ let mut map = HashMap::new();
12
+
13
+ hash.foreach(|key: Value, value: Value| {
14
+ let k: K = K::try_convert(key)
15
+ .map_err(|_| Error::new(ruby.exception_runtime_error(), "Key conversion failed"))?;
16
+
17
+ let values: Vec<V> = if let Ok(arr) = RArray::try_convert(value) {
18
+ // Value is an array, convert all elements
19
+ let mut vec = Vec::new();
20
+ for item_value in arr.into_iter() {
21
+ let v: V = V::try_convert(item_value).map_err(|_| {
22
+ Error::new(
23
+ ruby.exception_runtime_error(),
24
+ "Array element conversion failed",
25
+ )
26
+ })?;
27
+ vec.push(v);
28
+ }
29
+ vec
120
30
  } else {
121
- VM::raise_ex(AnyException::new(
122
- "Tantiny::UnexpectedNone",
123
- Some(&*format!("{}", std::any::type_name::<T>())))
124
- );
125
-
126
- self.unwrap()
127
- }
128
- }
31
+ // Value is a single value, wrap it in a Vec
32
+ let v: V = V::try_convert(value).map_err(|_| {
33
+ Error::new(ruby.exception_runtime_error(), "Value conversion failed")
34
+ })?;
35
+ vec![v]
36
+ };
37
+
38
+ map.insert(k, values);
39
+ Ok(ForEach::Continue)
40
+ })?;
41
+
42
+ Ok(map)
129
43
  }
130
44
 
131
- macro_rules! try_unwrap_params {
132
- (
133
- $param:ident: $type:ty,
134
- $( $rest:tt )*
135
- ) => {
136
- let _tmp = $param.map_err(|e| $crate::helpers::VM::raise_ex(e)).unwrap();
137
- let $param = <_ as $crate::helpers::TryUnwrap<$type>>::try_unwrap(_tmp);
138
-
139
- try_unwrap_params!($($rest)*)
140
- };
141
- (
142
- $param:ident,
143
- $( $rest:tt )*
144
- ) => {
145
- let $param = $param.map_err(|e| $crate::helpers::VM::raise_ex(e)).unwrap();
146
-
147
- try_unwrap_params!($($rest)*)
148
- };
149
-
150
- // Handle optional trailing commas.
151
- ( $param:ident: $type:ty ) => {
152
- try_unwrap_params!($param: $type,)
153
- };
154
- ( $param:ident ) => {
155
- try_unwrap_params!($param,)
156
- };
157
-
158
- () => {}
159
- }
160
-
161
- pub(crate) use try_unwrap_params;
162
-
163
- macro_rules! scaffold {
164
- ( $ruby_type:ident, $type:ty, $klass:literal ) => {
165
- $crate::helpers::class!($ruby_type);
166
-
167
- // There is a bug in Rutie which prevents using this macro
168
- // by resolving it by a full path, so the only workaround is:
169
- use crate::helpers::wrappable_struct;
170
-
171
- $crate::helpers::paste! {
172
- wrappable_struct!(
173
- $type,
174
- [<$type Wrapper>],
175
- [<$type:snake:upper _WRAPPER>]
176
- );
177
- }
178
-
179
- pub(crate) fn klass() -> $crate::helpers::Class {
180
- $crate::helpers::namespace().get_nested_class($klass)
181
- }
182
-
183
- impl $crate::helpers::TryUnwrap<$ruby_type> for $crate::helpers::AnyObject {
184
- fn try_unwrap(self) -> $ruby_type {
185
- let result = self.try_convert_to::<$ruby_type>();
186
- <_ as $crate::helpers::TryUnwrap<$ruby_type>>::try_unwrap(result)
187
- }
188
- }
189
-
190
- impl $crate::helpers::VerifiedObject for $ruby_type {
191
- fn is_correct_type<T: $crate::helpers::Object>(object: &T) -> bool {
192
- object.class() == klass()
193
- }
45
+ use tantivy::tokenizer::Language;
194
46
 
195
- fn error_message() -> &'static str {
196
- concat!("Error converting to ", stringify!($ruby_type), ".")
47
+ pub struct LanguageWrapper(pub Language);
48
+
49
+ impl TryFrom<String> for LanguageWrapper {
50
+ type Error = Error;
51
+
52
+ fn try_from(s: String) -> Result<Self, Self::Error> {
53
+ let lang = match s.as_str() {
54
+ "en" => Language::English,
55
+ "ar" => Language::Arabic,
56
+ "da" => Language::Danish,
57
+ "nl" => Language::Dutch,
58
+ "fi" => Language::Finnish,
59
+ "fr" => Language::French,
60
+ "de" => Language::German,
61
+ "el" => Language::Greek,
62
+ "hu" => Language::Hungarian,
63
+ "it" => Language::Italian,
64
+ "no" => Language::Norwegian,
65
+ "pt" => Language::Portuguese,
66
+ "ro" => Language::Romanian,
67
+ "ru" => Language::Russian,
68
+ "es" => Language::Spanish,
69
+ "sv" => Language::Swedish,
70
+ "ta" => Language::Tamil,
71
+ "tr" => Language::Turkish,
72
+ _ => {
73
+ let ruby = unsafe { Ruby::get_unchecked() };
74
+ return Err(Error::new(
75
+ ruby.exception_runtime_error(),
76
+ format!("Language '{}' is not supported.", s),
77
+ ));
197
78
  }
198
- }
79
+ };
80
+ Ok(LanguageWrapper(lang))
199
81
  }
200
82
  }
201
-
202
- pub(crate) use scaffold;