wreq 1.2.5 → 1.2.6

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/Cargo.lock +20 -13
  3. data/Cargo.toml +10 -2
  4. data/crates/wreq-util/src/emulate/macros.rs +12 -10
  5. data/crates/wreq-util/src/emulate/profile/chrome/header.rs +18 -3
  6. data/crates/wreq-util/src/emulate/profile/firefox/header.rs +16 -0
  7. data/crates/wreq-util/src/emulate/profile/opera/header.rs +6 -7
  8. data/crates/wreq-util/tests/client.rs +103 -1
  9. data/lib/wreq.rb +70 -45
  10. data/lib/wreq_ruby/body.rb +29 -11
  11. data/lib/wreq_ruby/client.rb +88 -55
  12. data/lib/wreq_ruby/cookie.rb +79 -19
  13. data/lib/wreq_ruby/emulate.rb +74 -6
  14. data/lib/wreq_ruby/error.rb +5 -7
  15. data/lib/wreq_ruby/http.rb +74 -0
  16. data/lib/wreq_ruby/response.rb +3 -0
  17. data/script/build_windows_gnu.ps1 +6 -0
  18. data/src/arch.rs +22 -0
  19. data/src/client/body/form.rs +2 -0
  20. data/src/client/body/json.rs +47 -14
  21. data/src/client/body/stream.rs +147 -43
  22. data/src/client/body.rs +11 -15
  23. data/src/client/param.rs +7 -7
  24. data/src/client/req.rs +87 -47
  25. data/src/client/resp.rs +23 -24
  26. data/src/client.rs +310 -230
  27. data/src/cookie.rs +280 -87
  28. data/src/emulate.rs +85 -50
  29. data/src/error.rs +198 -41
  30. data/src/extractor.rs +16 -76
  31. data/src/header.rs +146 -23
  32. data/src/http.rs +62 -33
  33. data/src/lib.rs +26 -20
  34. data/src/macros.rs +71 -46
  35. data/src/options.rs +284 -0
  36. data/src/rt.rs +22 -11
  37. data/src/serde/de/array_deserializer.rs +48 -0
  38. data/src/serde/de/array_enumerator.rs +59 -0
  39. data/src/serde/de/deserializer.rs +307 -0
  40. data/src/serde/de/enum_deserializer.rs +47 -0
  41. data/src/serde/de/hash_deserializer.rs +89 -0
  42. data/src/serde/de/number_deserializer.rs +51 -0
  43. data/src/serde/de/variant_deserializer.rs +101 -0
  44. data/src/serde/de.rs +33 -0
  45. data/src/serde/error.rs +146 -0
  46. data/src/serde/ser/enums.rs +14 -0
  47. data/src/serde/ser/map_serializer.rs +56 -0
  48. data/src/serde/ser/seq_serializer.rs +71 -0
  49. data/src/serde/ser/serializer.rs +194 -0
  50. data/src/serde/ser/struct_serializer.rs +106 -0
  51. data/src/serde/ser/struct_variant_serializer.rs +44 -0
  52. data/src/serde/ser/tuple_variant_serializer.rs +41 -0
  53. data/src/serde/ser.rs +18 -0
  54. data/src/serde/tests.rs +237 -0
  55. data/src/serde.rs +202 -0
  56. data/test/body_sender_test.rb +246 -0
  57. data/test/cookie_test.rb +211 -10
  58. data/test/json_precision_test.rb +209 -0
  59. data/test/option_validation_test.rb +311 -0
  60. data/test/value_semantics_test.rb +238 -0
  61. metadata +25 -2
  62. data/src/header/helper.rs +0 -112
@@ -0,0 +1,307 @@
1
+ use ::serde::forward_to_deserialize_any;
2
+ use magnus::{
3
+ Fixnum, Float, Integer, RArray, RBignum, RHash, RString, Ruby, Symbol, Value,
4
+ value::{Qfalse, Qtrue, ReprValue},
5
+ };
6
+
7
+ use super::super::{Error, MAX_JSON_NESTING};
8
+ use super::{
9
+ array_deserializer::ArrayDeserializer, enum_deserializer::EnumDeserializer,
10
+ hash_deserializer::HashDeserializer, number_deserializer::NumberDeserializer,
11
+ };
12
+ use crate::options::NATIVE_OPTION_TOKEN;
13
+
14
+ /// Implement typed Serde integer entry points with Magnus's checked conversions.
15
+ macro_rules! impl_deserialize_integers {
16
+ ($($method:ident => ($visit:ident, $convert:ident)),+ $(,)?) => {
17
+ $(
18
+ fn $method<Visitor>(self, visitor: Visitor) -> Result<Visitor::Value, Self::Error>
19
+ where
20
+ Visitor: ::serde::de::Visitor<'de>,
21
+ {
22
+ match Integer::from_value(self.value) {
23
+ Some(value) => visitor.$visit(value.$convert()?),
24
+ None => self.deserialize_any(visitor),
25
+ }
26
+ }
27
+ )+
28
+ };
29
+ }
30
+
31
+ /// Data model applied to a Ruby value during deserialization.
32
+ #[derive(Clone, Copy)]
33
+ pub(super) enum Mode {
34
+ /// Preserve the native Ruby-to-Serde conversion behavior.
35
+ Ruby,
36
+ /// Visit option names while skipping their values.
37
+ OptionKeys,
38
+ /// Enforce the JSON data model and preserve arbitrary-size numbers.
39
+ Json,
40
+ }
41
+
42
+ impl Mode {
43
+ /// Return whether JSON-specific validation is enabled.
44
+ fn is_json(self) -> bool {
45
+ matches!(self, Self::Json)
46
+ }
47
+ }
48
+
49
+ /// Serde deserializer over Ruby values.
50
+ pub(in crate::serde) struct Deserializer<'ruby> {
51
+ ruby: &'ruby Ruby,
52
+ value: Value,
53
+ depth: usize,
54
+ mode: Mode,
55
+ }
56
+
57
+ impl<'ruby> Deserializer<'ruby> {
58
+ /// Create a deserializer with native `serde_magnus` Ruby behavior.
59
+ pub(in crate::serde) fn new_ruby(ruby: &'ruby Ruby, value: Value) -> Self {
60
+ Self::with_mode(ruby, value, 0, Mode::Ruby)
61
+ }
62
+
63
+ /// Create a deserializer that validates option keys without reading values.
64
+ pub(in crate::serde) fn new_option_keys(ruby: &'ruby Ruby, value: Value) -> Self {
65
+ Self::with_mode(ruby, value, 0, Mode::OptionKeys)
66
+ }
67
+
68
+ /// Create a JSON deserializer with validation and arbitrary precision.
69
+ pub(super) fn new_json(ruby: &'ruby Ruby, value: Value) -> Self {
70
+ Self::with_mode(ruby, value, 0, Mode::Json)
71
+ }
72
+
73
+ /// Create a nested deserializer that inherits its conversion mode.
74
+ pub(super) fn with_mode(ruby: &'ruby Ruby, value: Value, depth: usize, mode: Mode) -> Self {
75
+ Self {
76
+ ruby,
77
+ value,
78
+ depth,
79
+ mode,
80
+ }
81
+ }
82
+
83
+ /// Validate and return the depth used by a nested container.
84
+ pub(super) fn nested_depth(&self) -> Result<usize, Error> {
85
+ let depth = self
86
+ .depth
87
+ .checked_add(1)
88
+ .ok_or_else(|| Error::message("JSON nesting depth overflow"))?;
89
+ if self.mode.is_json() && depth > MAX_JSON_NESTING {
90
+ Err(Error::message(format!(
91
+ "JSON nesting exceeds {MAX_JSON_NESTING} levels"
92
+ )))
93
+ } else {
94
+ Ok(depth)
95
+ }
96
+ }
97
+ }
98
+
99
+ impl<'de> ::serde::Deserializer<'de> for Deserializer<'_> {
100
+ type Error = Error;
101
+
102
+ fn deserialize_any<Visitor>(self, visitor: Visitor) -> Result<Visitor::Value, Self::Error>
103
+ where
104
+ Visitor: ::serde::de::Visitor<'de>,
105
+ {
106
+ if self.value.is_nil() {
107
+ return visitor.visit_unit();
108
+ }
109
+
110
+ if let Some(value) = Qtrue::from_value(self.value) {
111
+ return visitor.visit_bool(value.to_bool());
112
+ }
113
+
114
+ if let Some(value) = Qfalse::from_value(self.value) {
115
+ return visitor.visit_bool(value.to_bool());
116
+ }
117
+
118
+ if let Some(value) = Fixnum::from_value(self.value) {
119
+ return visitor.visit_i64(value.to_i64());
120
+ }
121
+
122
+ if let Some(value) = RBignum::from_value(self.value) {
123
+ if self.mode.is_json() {
124
+ let source: String = value.funcall_public("to_s", ())?;
125
+ return visitor.visit_map(NumberDeserializer::new(source));
126
+ }
127
+
128
+ return visitor.visit_i64(value.to_i64()?);
129
+ }
130
+
131
+ if let Some(value) = Float::from_value(self.value) {
132
+ let value = value.to_f64();
133
+ if self.mode.is_json() && !value.is_finite() {
134
+ return Err(Error::message("non-finite Float values are not valid JSON"));
135
+ }
136
+
137
+ return visitor.visit_f64(value);
138
+ }
139
+
140
+ if let Some(value) = RString::from_value(self.value) {
141
+ return visitor.visit_string(value.to_string()?);
142
+ }
143
+
144
+ if let Some(value) = Symbol::from_value(self.value) {
145
+ return visitor.visit_string(value.name()?.into_owned());
146
+ }
147
+
148
+ if let Some(value) = RArray::from_value(self.value) {
149
+ let depth = self.nested_depth()?;
150
+ return visitor.visit_seq(ArrayDeserializer::new(self.ruby, value, depth, self.mode));
151
+ }
152
+
153
+ if let Some(value) = RHash::from_value(self.value) {
154
+ let depth = self.nested_depth()?;
155
+ return visitor.visit_map(HashDeserializer::new(self.ruby, value, depth, self.mode)?);
156
+ }
157
+
158
+ Err(Error::type_error(format!(
159
+ "can't deserialize {}",
160
+ // SAFETY: conversion runs while the Ruby GVL is held.
161
+ unsafe { self.value.classname() }
162
+ )))
163
+ }
164
+
165
+ fn deserialize_bytes<Visitor>(self, _visitor: Visitor) -> Result<Visitor::Value, Self::Error>
166
+ where
167
+ Visitor: ::serde::de::Visitor<'de>,
168
+ {
169
+ Err(Error::type_error("can't deserialize into byte slice"))
170
+ }
171
+
172
+ fn deserialize_byte_buf<Visitor>(self, visitor: Visitor) -> Result<Visitor::Value, Self::Error>
173
+ where
174
+ Visitor: ::serde::de::Visitor<'de>,
175
+ {
176
+ if let Some(string) = RString::from_value(self.value) {
177
+ // SAFETY: the bytes are copied before any further Ruby API call.
178
+ visitor.visit_byte_buf(unsafe { string.as_slice() }.to_owned())
179
+ } else {
180
+ Err(Error::type_error(format!(
181
+ "no implicit conversion of {} to String",
182
+ // SAFETY: conversion runs while the Ruby GVL is held.
183
+ unsafe { self.value.classname() }
184
+ )))
185
+ }
186
+ }
187
+
188
+ fn deserialize_option<Visitor>(self, visitor: Visitor) -> Result<Visitor::Value, Self::Error>
189
+ where
190
+ Visitor: ::serde::de::Visitor<'de>,
191
+ {
192
+ if matches!(self.mode, Mode::OptionKeys) || self.value.is_nil() {
193
+ visitor.visit_none()
194
+ } else {
195
+ visitor.visit_some(self)
196
+ }
197
+ }
198
+
199
+ fn deserialize_enum<Visitor>(
200
+ self,
201
+ _name: &'static str,
202
+ _variants: &'static [&'static str],
203
+ visitor: Visitor,
204
+ ) -> Result<Visitor::Value, Self::Error>
205
+ where
206
+ Visitor: ::serde::de::Visitor<'de>,
207
+ {
208
+ if let Some(variant) = RString::from_value(self.value) {
209
+ return visitor.visit_enum(EnumDeserializer::new(
210
+ self.ruby,
211
+ variant.to_string()?,
212
+ self.ruby.qnil().as_value(),
213
+ self.depth,
214
+ self.mode,
215
+ ));
216
+ }
217
+
218
+ if let Some(hash) = RHash::from_value(self.value) {
219
+ if hash.len() == 1 {
220
+ let keys: RArray = hash.funcall("keys", ())?;
221
+ let key: String = keys.entry(0)?;
222
+ let value = hash
223
+ .get(key.as_str())
224
+ .unwrap_or_else(|| self.ruby.qnil().as_value());
225
+ return visitor.visit_enum(EnumDeserializer::new(
226
+ self.ruby, key, value, self.depth, self.mode,
227
+ ));
228
+ }
229
+ return Err(Error::type_error(format!(
230
+ "can't deserialize Hash of length {} to Enum",
231
+ hash.len()
232
+ )));
233
+ }
234
+
235
+ Err(Error::type_error(format!(
236
+ "can't deserialize {} to Enum",
237
+ // SAFETY: conversion runs while the Ruby GVL is held.
238
+ unsafe { self.value.classname() }
239
+ )))
240
+ }
241
+
242
+ fn deserialize_newtype_struct<Visitor>(
243
+ self,
244
+ name: &'static str,
245
+ visitor: Visitor,
246
+ ) -> Result<Visitor::Value, Self::Error>
247
+ where
248
+ Visitor: ::serde::de::Visitor<'de>,
249
+ {
250
+ if name == NATIVE_OPTION_TOKEN {
251
+ visitor.visit_unit()
252
+ } else {
253
+ visitor.visit_newtype_struct(self)
254
+ }
255
+ }
256
+
257
+ fn deserialize_ignored_any<Visitor>(
258
+ self,
259
+ visitor: Visitor,
260
+ ) -> Result<Visitor::Value, Self::Error>
261
+ where
262
+ Visitor: ::serde::de::Visitor<'de>,
263
+ {
264
+ visitor.visit_unit()
265
+ }
266
+
267
+ fn deserialize_identifier<Visitor>(
268
+ self,
269
+ visitor: Visitor,
270
+ ) -> Result<Visitor::Value, Self::Error>
271
+ where
272
+ Visitor: ::serde::de::Visitor<'de>,
273
+ {
274
+ if matches!(self.mode, Mode::OptionKeys) {
275
+ if let Some(value) = RString::from_value(self.value) {
276
+ return visitor.visit_string(value.to_string()?);
277
+ }
278
+ if let Some(value) = Symbol::from_value(self.value) {
279
+ return match value.name()? {
280
+ std::borrow::Cow::Borrowed(name) => visitor.visit_borrowed_str(name),
281
+ std::borrow::Cow::Owned(name) => visitor.visit_string(name),
282
+ };
283
+ }
284
+ return Err(Error::type_error("option keys must be Symbols or Strings"));
285
+ }
286
+
287
+ self.deserialize_any(visitor)
288
+ }
289
+
290
+ impl_deserialize_integers! {
291
+ deserialize_i8 => (visit_i8, to_i8),
292
+ deserialize_i16 => (visit_i16, to_i16),
293
+ deserialize_i32 => (visit_i32, to_i32),
294
+ deserialize_i64 => (visit_i64, to_i64),
295
+ deserialize_i128 => (visit_i128, to_i128),
296
+ deserialize_u8 => (visit_u8, to_u8),
297
+ deserialize_u16 => (visit_u16, to_u16),
298
+ deserialize_u32 => (visit_u32, to_u32),
299
+ deserialize_u64 => (visit_u64, to_u64),
300
+ deserialize_u128 => (visit_u128, to_u128),
301
+ }
302
+
303
+ forward_to_deserialize_any! {
304
+ <Visitor: Visitor<'de>>
305
+ bool f32 f64 char str string unit unit_struct seq tuple tuple_struct map struct
306
+ }
307
+ }
@@ -0,0 +1,47 @@
1
+ use ::serde::de::{DeserializeSeed, EnumAccess, value::StringDeserializer};
2
+ use magnus::{Ruby, Value};
3
+
4
+ use super::{Mode, VariantDeserializer};
5
+ use crate::serde::Error;
6
+
7
+ /// Serde enum access over a Ruby string or one-entry hash.
8
+ pub(super) struct EnumDeserializer<'ruby> {
9
+ ruby: &'ruby Ruby,
10
+ variant: String,
11
+ value: Value,
12
+ depth: usize,
13
+ mode: Mode,
14
+ }
15
+
16
+ impl<'ruby> EnumDeserializer<'ruby> {
17
+ /// Create enum access for a variant and its associated Ruby value.
18
+ pub(super) fn new(
19
+ ruby: &'ruby Ruby,
20
+ variant: String,
21
+ value: Value,
22
+ depth: usize,
23
+ mode: Mode,
24
+ ) -> Self {
25
+ Self {
26
+ ruby,
27
+ variant,
28
+ value,
29
+ depth,
30
+ mode,
31
+ }
32
+ }
33
+ }
34
+
35
+ impl<'ruby, 'de> EnumAccess<'de> for EnumDeserializer<'ruby> {
36
+ type Variant = VariantDeserializer<'ruby>;
37
+ type Error = Error;
38
+
39
+ fn variant_seed<Seed>(self, seed: Seed) -> Result<(Seed::Value, Self::Variant), Self::Error>
40
+ where
41
+ Seed: DeserializeSeed<'de>,
42
+ {
43
+ let variant = VariantDeserializer::new(self.ruby, self.value, self.depth, self.mode);
44
+ seed.deserialize(StringDeserializer::<Error>::new(self.variant))
45
+ .map(|value| (value, variant))
46
+ }
47
+ }
@@ -0,0 +1,89 @@
1
+ use std::iter::Peekable;
2
+
3
+ use ::serde::de::{DeserializeSeed, MapAccess};
4
+ use magnus::{RHash, RString, Ruby, Symbol, Value, r_hash::ForEach};
5
+
6
+ use super::{Deserializer, Mode, array_enumerator::ArrayEnumerator};
7
+ use crate::serde::Error;
8
+
9
+ /// Serde map access over a Ruby hash.
10
+ pub(super) struct HashDeserializer<'ruby> {
11
+ ruby: &'ruby Ruby,
12
+ hash: RHash,
13
+ keys: Peekable<ArrayEnumerator<'ruby>>,
14
+ depth: usize,
15
+ mode: Mode,
16
+ }
17
+
18
+ impl<'ruby> HashDeserializer<'ruby> {
19
+ /// Create map access while preserving Ruby hash insertion order.
20
+ pub(super) fn new(
21
+ ruby: &'ruby Ruby,
22
+ hash: RHash,
23
+ depth: usize,
24
+ mode: Mode,
25
+ ) -> Result<Self, Error> {
26
+ let keys = ruby.ary_new_capa(hash.len());
27
+ hash.foreach(|key: Value, _value: Value| {
28
+ keys.push(key)?;
29
+ Ok(ForEach::Continue)
30
+ })?;
31
+ Ok(Self {
32
+ ruby,
33
+ hash,
34
+ keys: ArrayEnumerator::new(ruby, keys).peekable(),
35
+ depth,
36
+ mode,
37
+ })
38
+ }
39
+
40
+ /// Reject object keys that JSON cannot represent.
41
+ fn validate_key(key: Value) -> Result<(), Error> {
42
+ if RString::from_value(key).is_some() || Symbol::from_value(key).is_some() {
43
+ Ok(())
44
+ } else {
45
+ Err(Error::message(
46
+ "JSON object keys must be String or Symbol values",
47
+ ))
48
+ }
49
+ }
50
+ }
51
+
52
+ impl<'de> MapAccess<'de> for HashDeserializer<'_> {
53
+ type Error = Error;
54
+
55
+ fn next_key_seed<Seed>(&mut self, seed: Seed) -> Result<Option<Seed::Value>, Self::Error>
56
+ where
57
+ Seed: DeserializeSeed<'de>,
58
+ {
59
+ match self.keys.peek() {
60
+ Some(Ok(key)) => {
61
+ if matches!(self.mode, Mode::Json) {
62
+ Self::validate_key(*key)?;
63
+ }
64
+ seed.deserialize(Deserializer::with_mode(
65
+ self.ruby, *key, self.depth, self.mode,
66
+ ))
67
+ .map(Some)
68
+ }
69
+ Some(Err(error)) => Err(Error::message(format!("failed to read map key: {error}"))),
70
+ None => Ok(None),
71
+ }
72
+ }
73
+
74
+ fn next_value_seed<Seed>(&mut self, seed: Seed) -> Result<Seed::Value, Self::Error>
75
+ where
76
+ Seed: DeserializeSeed<'de>,
77
+ {
78
+ match self.keys.next() {
79
+ Some(Ok(key)) => seed.deserialize(Deserializer::with_mode(
80
+ self.ruby,
81
+ self.hash.aref(key)?,
82
+ self.depth,
83
+ self.mode,
84
+ )),
85
+ Some(Err(error)) => Err(error),
86
+ None => Err(Error::message("map value has no matching key")),
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,51 @@
1
+ use ::serde::de::{
2
+ DeserializeSeed, MapAccess,
3
+ value::{BorrowedStrDeserializer, StringDeserializer},
4
+ };
5
+
6
+ use super::super::{Error, JSON_NUMBER_TOKEN};
7
+
8
+ /// Serde map representation used by `serde_json` for arbitrary-precision numbers.
9
+ pub(super) struct NumberDeserializer {
10
+ source: Option<String>,
11
+ }
12
+
13
+ impl NumberDeserializer {
14
+ /// Create a one-entry number map from a Ruby Integer decimal string.
15
+ pub(super) fn new(source: String) -> Self {
16
+ Self {
17
+ source: Some(source),
18
+ }
19
+ }
20
+ }
21
+
22
+ impl<'de> MapAccess<'de> for NumberDeserializer {
23
+ type Error = Error;
24
+
25
+ fn next_key_seed<Seed>(&mut self, seed: Seed) -> Result<Option<Seed::Value>, Self::Error>
26
+ where
27
+ Seed: DeserializeSeed<'de>,
28
+ {
29
+ if self.source.is_none() {
30
+ return Ok(None);
31
+ }
32
+
33
+ seed.deserialize(BorrowedStrDeserializer::<Error>::new(JSON_NUMBER_TOKEN))
34
+ .map(Some)
35
+ }
36
+
37
+ fn next_value_seed<Seed>(&mut self, seed: Seed) -> Result<Seed::Value, Self::Error>
38
+ where
39
+ Seed: DeserializeSeed<'de>,
40
+ {
41
+ let source = self
42
+ .source
43
+ .take()
44
+ .ok_or_else(|| Error::message("JSON number value is missing"))?;
45
+ seed.deserialize(StringDeserializer::<Error>::new(source))
46
+ }
47
+
48
+ fn size_hint(&self) -> Option<usize> {
49
+ Some(usize::from(self.source.is_some()))
50
+ }
51
+ }
@@ -0,0 +1,101 @@
1
+ use ::serde::de::{DeserializeSeed, Unexpected, VariantAccess};
2
+ use magnus::{RArray, RHash, Ruby, Value, value::ReprValue};
3
+
4
+ use super::{ArrayDeserializer, Deserializer, HashDeserializer, Mode};
5
+ use crate::serde::Error;
6
+
7
+ /// Serde access to the payload of a Ruby enum representation.
8
+ pub(super) struct VariantDeserializer<'ruby> {
9
+ ruby: &'ruby Ruby,
10
+ value: Value,
11
+ depth: usize,
12
+ mode: Mode,
13
+ }
14
+
15
+ impl<'ruby> VariantDeserializer<'ruby> {
16
+ /// Create variant access for a Ruby payload.
17
+ pub(super) fn new(ruby: &'ruby Ruby, value: Value, depth: usize, mode: Mode) -> Self {
18
+ Self {
19
+ ruby,
20
+ value,
21
+ depth,
22
+ mode,
23
+ }
24
+ }
25
+
26
+ /// Return the depth assigned to a container payload.
27
+ fn nested_depth(&self) -> Result<usize, Error> {
28
+ Deserializer::with_mode(self.ruby, self.value, self.depth, self.mode).nested_depth()
29
+ }
30
+ }
31
+
32
+ impl<'de> VariantAccess<'de> for VariantDeserializer<'_> {
33
+ type Error = Error;
34
+
35
+ fn unit_variant(self) -> Result<(), Self::Error> {
36
+ if self.value.is_nil() {
37
+ Ok(())
38
+ } else {
39
+ Err(::serde::de::Error::invalid_type(
40
+ Unexpected::Other(
41
+ // SAFETY: conversion runs while the Ruby GVL is held.
42
+ &unsafe { self.value.classname() },
43
+ ),
44
+ &"unit variant",
45
+ ))
46
+ }
47
+ }
48
+
49
+ fn newtype_variant_seed<Seed>(self, seed: Seed) -> Result<Seed::Value, Self::Error>
50
+ where
51
+ Seed: DeserializeSeed<'de>,
52
+ {
53
+ seed.deserialize(Deserializer::with_mode(
54
+ self.ruby, self.value, self.depth, self.mode,
55
+ ))
56
+ }
57
+
58
+ fn tuple_variant<Visitor>(
59
+ self,
60
+ _len: usize,
61
+ visitor: Visitor,
62
+ ) -> Result<Visitor::Value, Self::Error>
63
+ where
64
+ Visitor: ::serde::de::Visitor<'de>,
65
+ {
66
+ if let Some(array) = RArray::from_value(self.value) {
67
+ let depth = self.nested_depth()?;
68
+ visitor.visit_seq(ArrayDeserializer::new(self.ruby, array, depth, self.mode))
69
+ } else {
70
+ Err(::serde::de::Error::invalid_type(
71
+ Unexpected::Other(
72
+ // SAFETY: conversion runs while the Ruby GVL is held.
73
+ &unsafe { self.value.classname() },
74
+ ),
75
+ &"tuple variant",
76
+ ))
77
+ }
78
+ }
79
+
80
+ fn struct_variant<Visitor>(
81
+ self,
82
+ _fields: &'static [&'static str],
83
+ visitor: Visitor,
84
+ ) -> Result<Visitor::Value, Self::Error>
85
+ where
86
+ Visitor: ::serde::de::Visitor<'de>,
87
+ {
88
+ if let Some(hash) = RHash::from_value(self.value) {
89
+ let depth = self.nested_depth()?;
90
+ visitor.visit_map(HashDeserializer::new(self.ruby, hash, depth, self.mode)?)
91
+ } else {
92
+ Err(::serde::de::Error::invalid_type(
93
+ Unexpected::Other(
94
+ // SAFETY: conversion runs while the Ruby GVL is held.
95
+ &unsafe { self.value.classname() },
96
+ ),
97
+ &"struct variant",
98
+ ))
99
+ }
100
+ }
101
+ }
data/src/serde/de.rs ADDED
@@ -0,0 +1,33 @@
1
+ mod array_deserializer;
2
+ mod array_enumerator;
3
+ mod deserializer;
4
+ mod enum_deserializer;
5
+ mod hash_deserializer;
6
+ mod number_deserializer;
7
+ mod variant_deserializer;
8
+
9
+ use ::serde::Deserialize;
10
+ use magnus::{Ruby, Value};
11
+
12
+ use super::Error;
13
+ use array_deserializer::ArrayDeserializer;
14
+ pub(super) use deserializer::Deserializer;
15
+ use deserializer::Mode;
16
+ use hash_deserializer::HashDeserializer;
17
+ use variant_deserializer::VariantDeserializer;
18
+
19
+ /// Deserialize one Ruby value using native Ruby data model semantics.
20
+ pub(super) fn deserialize_ruby<'de, Output>(ruby: &Ruby, value: Value) -> Result<Output, Error>
21
+ where
22
+ Output: Deserialize<'de>,
23
+ {
24
+ Output::deserialize(Deserializer::new_ruby(ruby, value))
25
+ }
26
+
27
+ /// Deserialize one Ruby value using JSON-specific conversion rules.
28
+ pub(super) fn deserialize_json<'de, Output>(ruby: &Ruby, value: Value) -> Result<Output, Error>
29
+ where
30
+ Output: Deserialize<'de>,
31
+ {
32
+ Output::deserialize(Deserializer::new_json(ruby, value))
33
+ }