wreq 1.2.5 → 1.2.7

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.cargo/config.toml +4 -0
  3. data/Cargo.lock +135 -119
  4. data/Cargo.toml +11 -3
  5. data/Rakefile +6 -0
  6. data/crates/wreq-util/README.md +1 -1
  7. data/crates/wreq-util/examples/emulate.rs +3 -3
  8. data/crates/wreq-util/src/emulate/macros.rs +13 -11
  9. data/crates/wreq-util/src/emulate/profile/chrome/header.rs +18 -3
  10. data/crates/wreq-util/src/emulate/profile/firefox/header.rs +16 -0
  11. data/crates/wreq-util/src/emulate/profile/opera/header.rs +6 -7
  12. data/crates/wreq-util/tests/client.rs +103 -1
  13. data/docs/windows-gnu-tokio-crash.md +49 -3
  14. data/extconf.rb +4 -0
  15. data/lib/wreq.rb +70 -45
  16. data/lib/wreq_ruby/body.rb +29 -11
  17. data/lib/wreq_ruby/client.rb +88 -55
  18. data/lib/wreq_ruby/cookie.rb +79 -19
  19. data/lib/wreq_ruby/emulate.rb +74 -6
  20. data/lib/wreq_ruby/error.rb +5 -7
  21. data/lib/wreq_ruby/http.rb +74 -0
  22. data/lib/wreq_ruby/response.rb +3 -0
  23. data/script/rust_env.rb +85 -0
  24. data/src/arch.rs +22 -0
  25. data/src/client/body/form.rs +2 -0
  26. data/src/client/body/json.rs +47 -14
  27. data/src/client/body/stream.rs +147 -43
  28. data/src/client/body.rs +11 -15
  29. data/src/client/param.rs +7 -7
  30. data/src/client/req.rs +87 -47
  31. data/src/client/resp.rs +23 -24
  32. data/src/client.rs +310 -230
  33. data/src/cookie.rs +280 -87
  34. data/src/emulate.rs +85 -50
  35. data/src/error.rs +198 -41
  36. data/src/extractor.rs +16 -76
  37. data/src/header.rs +146 -23
  38. data/src/http.rs +62 -33
  39. data/src/lib.rs +26 -20
  40. data/src/macros.rs +71 -46
  41. data/src/options.rs +284 -0
  42. data/src/rt.rs +22 -11
  43. data/src/serde/de/array_deserializer.rs +48 -0
  44. data/src/serde/de/array_enumerator.rs +59 -0
  45. data/src/serde/de/deserializer.rs +307 -0
  46. data/src/serde/de/enum_deserializer.rs +47 -0
  47. data/src/serde/de/hash_deserializer.rs +89 -0
  48. data/src/serde/de/number_deserializer.rs +51 -0
  49. data/src/serde/de/variant_deserializer.rs +101 -0
  50. data/src/serde/de.rs +33 -0
  51. data/src/serde/error.rs +146 -0
  52. data/src/serde/ser/enums.rs +14 -0
  53. data/src/serde/ser/map_serializer.rs +56 -0
  54. data/src/serde/ser/seq_serializer.rs +71 -0
  55. data/src/serde/ser/serializer.rs +194 -0
  56. data/src/serde/ser/struct_serializer.rs +106 -0
  57. data/src/serde/ser/struct_variant_serializer.rs +44 -0
  58. data/src/serde/ser/tuple_variant_serializer.rs +41 -0
  59. data/src/serde/ser.rs +18 -0
  60. data/src/serde/tests.rs +237 -0
  61. data/src/serde.rs +202 -0
  62. data/test/body_sender_test.rb +246 -0
  63. data/test/cookie_test.rb +211 -10
  64. data/test/json_precision_test.rb +209 -0
  65. data/test/option_validation_test.rb +311 -0
  66. data/test/value_semantics_test.rb +238 -0
  67. data/wreq.gemspec +1 -1
  68. metadata +28 -4
  69. data/script/build_windows_gnu.ps1 +0 -264
  70. data/src/header/helper.rs +0 -112
@@ -0,0 +1,146 @@
1
+ use std::fmt;
2
+
3
+ use magnus::error::ErrorType;
4
+ use serde_path_to_error::Path;
5
+
6
+ use crate::error::contextualize_magnus_error;
7
+
8
+ /// Error produced by the local Ruby and Serde bridge.
9
+ #[derive(Debug)]
10
+ pub(crate) enum Error {
11
+ Runtime(String),
12
+ Type(String),
13
+ DuplicateField(&'static str),
14
+ Ruby(magnus::Error),
15
+ }
16
+
17
+ impl Error {
18
+ /// Create a bridge error from a human-readable message.
19
+ pub(super) fn message(message: impl Into<String>) -> Self {
20
+ Self::Runtime(message.into())
21
+ }
22
+
23
+ /// Create a type mismatch error.
24
+ pub(super) fn type_error(message: impl Into<String>) -> Self {
25
+ Self::Type(message.into())
26
+ }
27
+
28
+ /// Convert this bridge error into the matching Ruby exception.
29
+ pub(super) fn into_magnus(self, ruby: &magnus::Ruby) -> magnus::Error {
30
+ match self {
31
+ Self::Runtime(message) => magnus::Error::new(ruby.exception_runtime_error(), message),
32
+ Self::Type(message) => magnus::Error::new(ruby.exception_type_error(), message),
33
+ Self::DuplicateField(field) => magnus::Error::new(
34
+ ruby.exception_runtime_error(),
35
+ format!("duplicate field `{field}`"),
36
+ ),
37
+ Self::Ruby(error) => error,
38
+ }
39
+ }
40
+
41
+ /// Convert an option value error into Ruby's normal argument categories.
42
+ pub(super) fn into_option_magnus(
43
+ self,
44
+ ruby: &magnus::Ruby,
45
+ path: Option<&Path>,
46
+ ) -> magnus::Error {
47
+ match self {
48
+ Self::Runtime(message) => magnus::Error::new(
49
+ ruby.exception_arg_error(),
50
+ contextualize_message(path, message),
51
+ ),
52
+ Self::Type(message) => magnus::Error::new(
53
+ ruby.exception_type_error(),
54
+ contextualize_message(path, message),
55
+ ),
56
+ Self::DuplicateField(field) => magnus::Error::new(
57
+ ruby.exception_arg_error(),
58
+ format!("duplicate option: :{field}"),
59
+ ),
60
+ Self::Ruby(error) if error.is_kind_of(ruby.exception_range_error()) => {
61
+ magnus::Error::new(
62
+ ruby.exception_arg_error(),
63
+ magnus_error_message(&error, path),
64
+ )
65
+ }
66
+ Self::Ruby(error) => match path {
67
+ Some(path) => {
68
+ contextualize_magnus_error(error, format_args!("invalid value for :{path}"))
69
+ }
70
+ None => error,
71
+ },
72
+ }
73
+ }
74
+ }
75
+
76
+ /// Prefix an error message when Serde identified the failing option path.
77
+ fn contextualize_message(path: Option<&Path>, message: String) -> String {
78
+ match path {
79
+ Some(path) => format!("invalid value for :{path}: {message}"),
80
+ None => message,
81
+ }
82
+ }
83
+
84
+ /// Build the final Ruby error message without an intermediate context String.
85
+ fn magnus_error_message(error: &magnus::Error, path: Option<&Path>) -> String {
86
+ match (path, error.error_type()) {
87
+ (Some(path), ErrorType::Error(_, message)) => {
88
+ format!("invalid value for :{path}: {message}")
89
+ }
90
+ (Some(path), ErrorType::Exception(exception)) => {
91
+ format!("invalid value for :{path}: {exception}")
92
+ }
93
+ (Some(path), ErrorType::Jump(_)) => format!("invalid value for :{path}: {error}"),
94
+ (None, ErrorType::Error(_, message)) => message.as_ref().to_owned(),
95
+ (None, _) => error.to_string(),
96
+ }
97
+ }
98
+
99
+ impl fmt::Display for Error {
100
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
101
+ match self {
102
+ Self::Runtime(message) | Self::Type(message) => formatter.write_str(message),
103
+ Self::DuplicateField(field) => write!(formatter, "duplicate field `{field}`"),
104
+ Self::Ruby(error) => error.fmt(formatter),
105
+ }
106
+ }
107
+ }
108
+
109
+ impl std::error::Error for Error {}
110
+
111
+ impl ::serde::ser::Error for Error {
112
+ fn custom<T>(message: T) -> Self
113
+ where
114
+ T: fmt::Display,
115
+ {
116
+ Self::message(message.to_string())
117
+ }
118
+ }
119
+
120
+ impl ::serde::de::Error for Error {
121
+ fn custom<T>(message: T) -> Self
122
+ where
123
+ T: fmt::Display,
124
+ {
125
+ Self::message(message.to_string())
126
+ }
127
+
128
+ fn invalid_type(
129
+ unexpected: ::serde::de::Unexpected<'_>,
130
+ expected: &dyn ::serde::de::Expected,
131
+ ) -> Self {
132
+ Self::type_error(format!(
133
+ "invalid type: expected {expected}, got {unexpected}"
134
+ ))
135
+ }
136
+
137
+ fn duplicate_field(field: &'static str) -> Self {
138
+ Self::DuplicateField(field)
139
+ }
140
+ }
141
+
142
+ impl From<magnus::Error> for Error {
143
+ fn from(error: magnus::Error) -> Self {
144
+ Self::Ruby(error)
145
+ }
146
+ }
@@ -0,0 +1,14 @@
1
+ use magnus::{IntoValue, Ruby, Value};
2
+
3
+ use crate::serde::Error;
4
+
5
+ /// Wrap serialized enum data in the one-entry hash used by `serde_magnus`.
6
+ pub(super) fn nest(
7
+ ruby: &Ruby,
8
+ variant: &'static str,
9
+ data: impl IntoValue,
10
+ ) -> Result<Value, Error> {
11
+ let hash = ruby.hash_new();
12
+ hash.aset(variant, data)?;
13
+ Ok(hash.into_value_with(ruby))
14
+ }
@@ -0,0 +1,56 @@
1
+ use ::serde::{Serialize, ser::SerializeMap};
2
+ use magnus::{IntoValue, RHash, Ruby, Value};
3
+
4
+ use super::Serializer;
5
+ use crate::serde::Error;
6
+
7
+ /// Serde map serializer backed by a Ruby hash.
8
+ pub(super) struct MapSerializer<'ruby> {
9
+ ruby: &'ruby Ruby,
10
+ hash: RHash,
11
+ key: Option<Value>,
12
+ }
13
+
14
+ impl<'ruby> MapSerializer<'ruby> {
15
+ /// Create a map serializer for an allocated Ruby hash.
16
+ pub(super) fn new(ruby: &'ruby Ruby, hash: RHash) -> Self {
17
+ Self {
18
+ ruby,
19
+ hash,
20
+ key: None,
21
+ }
22
+ }
23
+ }
24
+
25
+ impl SerializeMap for MapSerializer<'_> {
26
+ type Ok = Value;
27
+ type Error = Error;
28
+
29
+ fn serialize_key<T>(&mut self, key: &T) -> Result<(), Self::Error>
30
+ where
31
+ T: Serialize + ?Sized,
32
+ {
33
+ self.key = Some(key.serialize(Serializer::new(self.ruby))?);
34
+ Ok(())
35
+ }
36
+
37
+ fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
38
+ where
39
+ T: Serialize + ?Sized,
40
+ {
41
+ let key = self
42
+ .key
43
+ .take()
44
+ .ok_or_else(|| Error::message("map value has no matching key"))?;
45
+ self.hash
46
+ .aset(key, value.serialize(Serializer::new(self.ruby))?)
47
+ .map_err(Into::into)
48
+ }
49
+
50
+ fn end(self) -> Result<Self::Ok, Self::Error> {
51
+ if self.key.is_some() {
52
+ return Err(Error::message("map key has no matching value"));
53
+ }
54
+ Ok(self.hash.into_value_with(self.ruby))
55
+ }
56
+ }
@@ -0,0 +1,71 @@
1
+ use ::serde::{
2
+ Serialize,
3
+ ser::{SerializeSeq, SerializeTuple, SerializeTupleStruct},
4
+ };
5
+ use magnus::{IntoValue, RArray, Ruby, Value};
6
+
7
+ use super::Serializer;
8
+ use crate::serde::Error;
9
+
10
+ /// Serde sequence serializer backed by a Ruby array.
11
+ pub(super) struct SeqSerializer<'ruby> {
12
+ ruby: &'ruby Ruby,
13
+ array: RArray,
14
+ }
15
+
16
+ impl<'ruby> SeqSerializer<'ruby> {
17
+ /// Create a sequence serializer for an allocated Ruby array.
18
+ pub(super) fn new(ruby: &'ruby Ruby, array: RArray) -> Self {
19
+ Self { ruby, array }
20
+ }
21
+ }
22
+
23
+ impl SerializeSeq for SeqSerializer<'_> {
24
+ type Ok = Value;
25
+ type Error = Error;
26
+
27
+ fn serialize_element<T>(&mut self, element: &T) -> Result<(), Self::Error>
28
+ where
29
+ T: Serialize + ?Sized,
30
+ {
31
+ self.array
32
+ .push(element.serialize(Serializer::new(self.ruby))?)
33
+ .map_err(Into::into)
34
+ }
35
+
36
+ fn end(self) -> Result<Self::Ok, Self::Error> {
37
+ Ok(self.array.into_value_with(self.ruby))
38
+ }
39
+ }
40
+
41
+ impl SerializeTuple for SeqSerializer<'_> {
42
+ type Ok = Value;
43
+ type Error = Error;
44
+
45
+ fn serialize_element<T>(&mut self, element: &T) -> Result<(), Self::Error>
46
+ where
47
+ T: Serialize + ?Sized,
48
+ {
49
+ SerializeSeq::serialize_element(self, element)
50
+ }
51
+
52
+ fn end(self) -> Result<Self::Ok, Self::Error> {
53
+ SerializeSeq::end(self)
54
+ }
55
+ }
56
+
57
+ impl SerializeTupleStruct for SeqSerializer<'_> {
58
+ type Ok = Value;
59
+ type Error = Error;
60
+
61
+ fn serialize_field<T>(&mut self, field: &T) -> Result<(), Self::Error>
62
+ where
63
+ T: Serialize + ?Sized,
64
+ {
65
+ SerializeSeq::serialize_element(self, field)
66
+ }
67
+
68
+ fn end(self) -> Result<Self::Ok, Self::Error> {
69
+ SerializeSeq::end(self)
70
+ }
71
+ }
@@ -0,0 +1,194 @@
1
+ use ::serde::Serialize;
2
+ use magnus::{IntoValue, Ruby, Value};
3
+
4
+ use super::super::Error;
5
+ use super::{
6
+ enums::nest, map_serializer::MapSerializer, seq_serializer::SeqSerializer,
7
+ struct_serializer::StructSerializer, struct_variant_serializer::StructVariantSerializer,
8
+ tuple_variant_serializer::TupleVariantSerializer,
9
+ };
10
+
11
+ /// Implement primitive numeric serialization through Magnus's `IntoValue`.
12
+ macro_rules! impl_serialize_numbers {
13
+ ($($method:ident => $type:ty),+ $(,)?) => {
14
+ $(
15
+ fn $method(self, value: $type) -> Result<Self::Ok, Self::Error> {
16
+ Ok(value.into_value_with(self.ruby))
17
+ }
18
+ )+
19
+ };
20
+ }
21
+
22
+ /// Serde serializer that creates Ruby values.
23
+ pub(super) struct Serializer<'ruby> {
24
+ ruby: &'ruby Ruby,
25
+ }
26
+
27
+ impl<'ruby> Serializer<'ruby> {
28
+ /// Create a serializer with upstream `serde_magnus` behavior.
29
+ pub(super) fn new(ruby: &'ruby Ruby) -> Self {
30
+ Self { ruby }
31
+ }
32
+ }
33
+
34
+ impl<'ruby> ::serde::Serializer for Serializer<'ruby> {
35
+ type Ok = Value;
36
+ type Error = Error;
37
+
38
+ type SerializeSeq = SeqSerializer<'ruby>;
39
+ type SerializeTuple = SeqSerializer<'ruby>;
40
+ type SerializeTupleStruct = SeqSerializer<'ruby>;
41
+ type SerializeTupleVariant = TupleVariantSerializer<'ruby>;
42
+ type SerializeMap = MapSerializer<'ruby>;
43
+ type SerializeStruct = StructSerializer<'ruby>;
44
+ type SerializeStructVariant = StructVariantSerializer<'ruby>;
45
+
46
+ fn serialize_bool(self, value: bool) -> Result<Self::Ok, Self::Error> {
47
+ Ok(value.into_value_with(self.ruby))
48
+ }
49
+
50
+ impl_serialize_numbers! {
51
+ serialize_i8 => i8,
52
+ serialize_i16 => i16,
53
+ serialize_i32 => i32,
54
+ serialize_i64 => i64,
55
+ serialize_i128 => i128,
56
+ serialize_u8 => u8,
57
+ serialize_u16 => u16,
58
+ serialize_u32 => u32,
59
+ serialize_u64 => u64,
60
+ serialize_u128 => u128,
61
+ serialize_f32 => f32,
62
+ serialize_f64 => f64,
63
+ }
64
+
65
+ fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
66
+ Ok(value.into_value_with(self.ruby))
67
+ }
68
+
69
+ fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
70
+ Ok(value.into_value_with(self.ruby))
71
+ }
72
+
73
+ fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
74
+ Ok(self.ruby.str_from_slice(value).into_value_with(self.ruby))
75
+ }
76
+
77
+ fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
78
+ self.serialize_unit()
79
+ }
80
+
81
+ fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
82
+ where
83
+ T: Serialize + ?Sized,
84
+ {
85
+ value.serialize(self)
86
+ }
87
+
88
+ fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
89
+ Ok(().into_value_with(self.ruby))
90
+ }
91
+
92
+ fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
93
+ self.serialize_unit()
94
+ }
95
+
96
+ fn serialize_unit_variant(
97
+ self,
98
+ _name: &'static str,
99
+ _index: u32,
100
+ variant: &'static str,
101
+ ) -> Result<Self::Ok, Self::Error> {
102
+ self.serialize_str(variant)
103
+ }
104
+
105
+ fn serialize_newtype_struct<T>(
106
+ self,
107
+ _name: &'static str,
108
+ value: &T,
109
+ ) -> Result<Self::Ok, Self::Error>
110
+ where
111
+ T: Serialize + ?Sized,
112
+ {
113
+ value.serialize(self)
114
+ }
115
+
116
+ fn serialize_newtype_variant<T>(
117
+ self,
118
+ _name: &'static str,
119
+ _index: u32,
120
+ variant: &'static str,
121
+ value: &T,
122
+ ) -> Result<Self::Ok, Self::Error>
123
+ where
124
+ T: Serialize + ?Sized,
125
+ {
126
+ nest(
127
+ self.ruby,
128
+ variant,
129
+ value.serialize(Serializer::new(self.ruby))?,
130
+ )
131
+ }
132
+
133
+ fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
134
+ Ok(SeqSerializer::new(
135
+ self.ruby,
136
+ self.ruby.ary_new_capa(len.unwrap_or(0)),
137
+ ))
138
+ }
139
+
140
+ fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
141
+ self.serialize_seq(Some(len))
142
+ }
143
+
144
+ fn serialize_tuple_struct(
145
+ self,
146
+ _name: &'static str,
147
+ len: usize,
148
+ ) -> Result<Self::SerializeTupleStruct, Self::Error> {
149
+ self.serialize_seq(Some(len))
150
+ }
151
+
152
+ fn serialize_tuple_variant(
153
+ self,
154
+ _name: &'static str,
155
+ _index: u32,
156
+ variant: &'static str,
157
+ len: usize,
158
+ ) -> Result<Self::SerializeTupleVariant, Self::Error> {
159
+ Ok(TupleVariantSerializer::new(
160
+ self.ruby,
161
+ variant,
162
+ self.ruby.ary_new_capa(len),
163
+ ))
164
+ }
165
+
166
+ fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
167
+ Ok(MapSerializer::new(
168
+ self.ruby,
169
+ self.ruby.hash_new_capa(len.unwrap_or(0)),
170
+ ))
171
+ }
172
+
173
+ fn serialize_struct(
174
+ self,
175
+ name: &'static str,
176
+ len: usize,
177
+ ) -> Result<Self::SerializeStruct, Self::Error> {
178
+ Ok(StructSerializer::new(self.ruby, name, len))
179
+ }
180
+
181
+ fn serialize_struct_variant(
182
+ self,
183
+ _name: &'static str,
184
+ _index: u32,
185
+ variant: &'static str,
186
+ len: usize,
187
+ ) -> Result<Self::SerializeStructVariant, Self::Error> {
188
+ Ok(StructVariantSerializer::new(
189
+ self.ruby,
190
+ variant,
191
+ self.ruby.hash_new_capa(len),
192
+ ))
193
+ }
194
+ }
@@ -0,0 +1,106 @@
1
+ use ::serde::{Serialize, ser::SerializeStruct};
2
+ use magnus::{Integer, IntoValue, RHash, RString, Ruby, Value, value::ReprValue};
3
+
4
+ use super::Serializer;
5
+ use crate::serde::{Error, JSON_NUMBER_TOKEN};
6
+
7
+ /// Serde struct serializer, including `serde_json` arbitrary-precision numbers.
8
+ pub(super) enum StructSerializer<'ruby> {
9
+ Map {
10
+ ruby: &'ruby Ruby,
11
+ hash: RHash,
12
+ },
13
+ Number {
14
+ ruby: &'ruby Ruby,
15
+ value: Option<Value>,
16
+ },
17
+ }
18
+
19
+ impl<'ruby> StructSerializer<'ruby> {
20
+ /// Create the serializer selected by the Serde struct name.
21
+ pub(super) fn new(ruby: &'ruby Ruby, name: &'static str, len: usize) -> Self {
22
+ if name == JSON_NUMBER_TOKEN {
23
+ Self::Number { ruby, value: None }
24
+ } else {
25
+ Self::Map {
26
+ ruby,
27
+ hash: ruby.hash_new_capa(len),
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ impl SerializeStruct for StructSerializer<'_> {
34
+ type Ok = Value;
35
+ type Error = Error;
36
+
37
+ fn serialize_field<T>(&mut self, name: &'static str, value: &T) -> Result<(), Self::Error>
38
+ where
39
+ T: Serialize + ?Sized,
40
+ {
41
+ match self {
42
+ Self::Map { ruby, hash } => hash
43
+ .aset(
44
+ ruby.to_symbol(name),
45
+ value.serialize(Serializer::new(ruby))?,
46
+ )
47
+ .map_err(Into::into),
48
+ Self::Number {
49
+ ruby,
50
+ value: output,
51
+ } => {
52
+ if name != JSON_NUMBER_TOKEN {
53
+ return Err(Error::message("invalid arbitrary-precision number field"));
54
+ }
55
+
56
+ if output.is_some() {
57
+ return Err(Error::message(
58
+ "arbitrary-precision number has duplicate fields",
59
+ ));
60
+ }
61
+
62
+ let source = value.serialize(Serializer::new(ruby))?;
63
+ let source = RString::from_value(source)
64
+ .ok_or_else(|| Error::message("JSON number token must be a String"))?
65
+ .to_string()?;
66
+ *output = Some(number_to_ruby(ruby, &source)?);
67
+ Ok(())
68
+ }
69
+ }
70
+ }
71
+
72
+ fn end(self) -> Result<Self::Ok, Self::Error> {
73
+ match self {
74
+ Self::Map { ruby, hash } => Ok(hash.into_value_with(ruby)),
75
+ Self::Number { value, .. } => {
76
+ value.ok_or_else(|| Error::message("JSON number token is missing"))
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ /// Convert a validated JSON number token into a Ruby Integer or Float.
83
+ fn number_to_ruby(ruby: &Ruby, source: &str) -> Result<Value, Error> {
84
+ if is_integral_number(source) {
85
+ integer_to_ruby(ruby, source)
86
+ } else {
87
+ let value = source.parse::<f64>().map_err(|error| {
88
+ Error::message(format!("failed to convert JSON number {source}: {error}"))
89
+ })?;
90
+ Ok(ruby.float_from_f64(value).as_value())
91
+ }
92
+ }
93
+
94
+ /// Convert a decimal integer token into an arbitrary-precision Ruby Integer.
95
+ fn integer_to_ruby(ruby: &Ruby, source: &str) -> Result<Value, Error> {
96
+ let source = ruby.str_new(source);
97
+ let value: Integer = ruby.module_kernel().funcall("Integer", (source, 10))?;
98
+ Ok(value.as_value())
99
+ }
100
+
101
+ /// Return whether a validated JSON number token is integral.
102
+ fn is_integral_number(source: &str) -> bool {
103
+ !source
104
+ .bytes()
105
+ .any(|byte| matches!(byte, b'.' | b'e' | b'E'))
106
+ }
@@ -0,0 +1,44 @@
1
+ use ::serde::{Serialize, ser::SerializeStructVariant};
2
+ use magnus::{RHash, Ruby, Value};
3
+
4
+ use super::{Serializer, enums::nest};
5
+ use crate::serde::Error;
6
+
7
+ /// Serde struct-variant serializer backed by a Ruby hash.
8
+ pub(super) struct StructVariantSerializer<'ruby> {
9
+ ruby: &'ruby Ruby,
10
+ variant: &'static str,
11
+ hash: RHash,
12
+ }
13
+
14
+ impl<'ruby> StructVariantSerializer<'ruby> {
15
+ /// Create a struct-variant serializer for an allocated Ruby hash.
16
+ pub(super) fn new(ruby: &'ruby Ruby, variant: &'static str, hash: RHash) -> Self {
17
+ Self {
18
+ ruby,
19
+ variant,
20
+ hash,
21
+ }
22
+ }
23
+ }
24
+
25
+ impl SerializeStructVariant for StructVariantSerializer<'_> {
26
+ type Ok = Value;
27
+ type Error = Error;
28
+
29
+ fn serialize_field<T>(&mut self, name: &'static str, value: &T) -> Result<(), Self::Error>
30
+ where
31
+ T: Serialize + ?Sized,
32
+ {
33
+ self.hash
34
+ .aset(
35
+ self.ruby.to_symbol(name),
36
+ value.serialize(Serializer::new(self.ruby))?,
37
+ )
38
+ .map_err(Into::into)
39
+ }
40
+
41
+ fn end(self) -> Result<Self::Ok, Self::Error> {
42
+ nest(self.ruby, self.variant, self.hash)
43
+ }
44
+ }
@@ -0,0 +1,41 @@
1
+ use ::serde::{Serialize, ser::SerializeTupleVariant};
2
+ use magnus::{RArray, Ruby, Value};
3
+
4
+ use super::{Serializer, enums::nest};
5
+ use crate::serde::Error;
6
+
7
+ /// Serde tuple-variant serializer backed by a Ruby array.
8
+ pub(super) struct TupleVariantSerializer<'ruby> {
9
+ ruby: &'ruby Ruby,
10
+ variant: &'static str,
11
+ array: RArray,
12
+ }
13
+
14
+ impl<'ruby> TupleVariantSerializer<'ruby> {
15
+ /// Create a tuple-variant serializer for an allocated Ruby array.
16
+ pub(super) fn new(ruby: &'ruby Ruby, variant: &'static str, array: RArray) -> Self {
17
+ Self {
18
+ ruby,
19
+ variant,
20
+ array,
21
+ }
22
+ }
23
+ }
24
+
25
+ impl SerializeTupleVariant for TupleVariantSerializer<'_> {
26
+ type Ok = Value;
27
+ type Error = Error;
28
+
29
+ fn serialize_field<T>(&mut self, field: &T) -> Result<(), Self::Error>
30
+ where
31
+ T: Serialize + ?Sized,
32
+ {
33
+ self.array
34
+ .push(field.serialize(Serializer::new(self.ruby))?)
35
+ .map_err(Into::into)
36
+ }
37
+
38
+ fn end(self) -> Result<Self::Ok, Self::Error> {
39
+ nest(self.ruby, self.variant, self.array)
40
+ }
41
+ }
data/src/serde/ser.rs ADDED
@@ -0,0 +1,18 @@
1
+ mod enums;
2
+ mod map_serializer;
3
+ mod seq_serializer;
4
+ mod serializer;
5
+ mod struct_serializer;
6
+ mod struct_variant_serializer;
7
+ mod tuple_variant_serializer;
8
+
9
+ use ::serde::Serialize;
10
+ use magnus::{Ruby, Value};
11
+
12
+ use super::Error;
13
+ use serializer::Serializer;
14
+
15
+ /// Serialize any Serde value into Ruby values.
16
+ pub(super) fn serialize(ruby: &Ruby, value: &(impl Serialize + ?Sized)) -> Result<Value, Error> {
17
+ value.serialize(Serializer::new(ruby))
18
+ }