From 6ec689b3762a1f8090d97045a76d8d7282dd1fe3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 13:26:21 +0200 Subject: [PATCH 01/95] x-www-form-urlencoded meets Serde --- .gitignore | 2 + .travis.yml | 5 + Cargo.toml | 13 ++ LICENSE-APACHE | 176 +++++++++++++++++++ LICENSE-MIT | 25 +++ README.md | 50 ++++++ src/de.rs | 90 ++++++++++ src/lib.rs | 11 ++ src/ser/key.rs | 292 +++++++++++++++++++++++++++++++ src/ser/mod.rs | 445 +++++++++++++++++++++++++++++++++++++++++++++++ src/ser/pair.rs | 330 +++++++++++++++++++++++++++++++++++ src/ser/value.rs | 322 ++++++++++++++++++++++++++++++++++ 12 files changed, 1761 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 src/de.rs create mode 100644 src/lib.rs create mode 100644 src/ser/key.rs create mode 100644 src/ser/mod.rs create mode 100644 src/ser/pair.rs create mode 100644 src/ser/value.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a9d37c56 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..4ecd9b6b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: rust +rust: + - nightly + - beta + - stable diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..a5098d9b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "serde_urlencoded" +version = "0.1.0" +authors = ["Anthony Ramine "] +license = "MIT/Apache-2.0" +repository = "https://github.com/nox/serde_urlencoded" +documentation = "https://docs.rs/crate/serde_urlencoded" +description = "`x-www-form-urlencoded` meets Serde" +keywords = ["serde", "serialization", "urlencoded"] + +[dependencies] +serde = "0.8.7" +url = "1.0.0" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..1b5ec8b7 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..39f6303a --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Anthony Ramine + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..0c9fe8fe --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +`x-www-form-urlencoded` meets Serde +=================================== + +This crate is a Rust library for serialising to and deserialising from +the [`application/x-www-form-urlencoded`][urlencoded] format. It is built +upon [Serde], a high performance generic serialization framework and [rust-url], +a URL parser for Rust. + +[rust-url]: https://github.com/servo/rust-url +[Serde]: https://github.com/serde-rs/serde +[urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded + +Installation +============ + +This crate works with Cargo and can be found on +[crates.io] with a `Cargo.toml` like: + +```toml +[dependencies] +serde_urlencoded = "0.1" +``` + +[crates.io]: https://crates.io/crates/serde_urlencoded + +## Getting help + +Serde developers live in the #serde channel on +[`irc.mozilla.org`](https://wiki.mozilla.org/IRC) and most rust-url developers +live in the #servo one. The #rust channel is also a good resource with generally +faster response time but less specific knowledge about Serde, rust-url or this +crate. If IRC is not your thing, we are happy to respond to [GitHub +issues](https://github.com/nox/serde_urlencoded/issues/new) as well. + +## License + +Serde is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/src/de.rs b/src/de.rs new file mode 100644 index 00000000..ec84ff22 --- /dev/null +++ b/src/de.rs @@ -0,0 +1,90 @@ +//! Deserialization support for the `application/x-www-form-urlencoded` format. + +use serde::de; +use serde::de::value::MapDeserializer; +use std::borrow::Cow; +use std::marker::PhantomData; +use url::form_urlencoded::Parse; + +pub use serde::de::value::Error; + +/// A deserializer for the `application/x-www-form-urlencoded` format. +/// +/// * Supported top-level outputs are structs, maps and sequences of pairs, +/// with or without a given length. +/// +/// * Main `deserialize` methods defers to `deserialize_map`. +/// +/// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` +/// defers to `deserialize`. +pub struct Deserializer<'a, T> { + deserializer: MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>, + marker: PhantomData, +} + +impl<'a, T> de::Deserializer for Deserializer<'a, T> +{ + type Error = Error; + + fn deserialize( + &mut self, visitor: V) + -> Result + where V: de::Visitor, + { + self.deserialize_map(visitor) + } + + fn deserialize_map( + &mut self, mut visitor: V) + -> Result + where V: de::Visitor, + { + visitor.visit_map(&mut self.deserializer) + } + + fn deserialize_seq( + &mut self, mut visitor: V) + -> Result + where V: de::Visitor, + { + visitor.visit_seq(&mut self.deserializer) + } + + fn deserialize_seq_fixed_size( + &mut self, _len: usize, mut visitor: V) + -> Result + where V: de::Visitor + { + visitor.visit_seq(&mut self.deserializer) + } + + forward_to_deserialize! { + bool + usize + u8 + u16 + u32 + u64 + isize + i8 + i16 + i32 + i64 + f32 + f64 + char + str + string + unit + option + bytes + unit_struct + newtype_struct + tuple_struct + struct + struct_field + tuple + enum + ignored_any + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..95a0ad60 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,11 @@ +//! `x-www-form-urlencoded` meets Serde + +#[macro_use] +extern crate serde; +extern crate url; + +pub mod de; +pub mod ser; + +pub use de::Deserializer; +pub use ser::Serializer; diff --git a/src/ser/key.rs b/src/ser/key.rs new file mode 100644 index 00000000..a26c5638 --- /dev/null +++ b/src/ser/key.rs @@ -0,0 +1,292 @@ +use serde::{Serialize, Serializer}; +use ser::Error; +use std::borrow::Cow; +use std::str; + +pub struct MapKeySerializer<'key>(&'key mut Option>); + +impl<'key> MapKeySerializer<'key> { + pub fn new(output: &'key mut Option>) -> Self { + MapKeySerializer(output) + } + + fn set_key(&mut self, key: T) -> Result<(), Error> + where T: Into> + { + *self.0 = Some(key.into()); + Ok(()) + } +} + +impl<'key> Serializer for MapKeySerializer<'key> { + type Error = Error; + type SeqState = (); + type TupleState = (); + type TupleStructState = (); + type TupleVariantState = (); + type MapState = (); + type StructState = (); + type StructVariantState = (); + + fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_isize(&mut self, v: isize) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_i8(&mut self, v: i8) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_i16(&mut self, v: i16) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_i32(&mut self, v: i32) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_i64(&mut self, v: i64) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_usize(&mut self, v: usize) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_u8(&mut self, v: u8) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_u16(&mut self, v: u16) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_u32(&mut self, v: u32) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_u64(&mut self, v: u64) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_f32(&mut self, v: f32) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_f64(&mut self, v: f64) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_char(&mut self, v: char) -> Result<(), Error> { + self.set_key(v.to_string()) + } + + fn serialize_str(&mut self, value: &str) -> Result<(), Error> { + self.set_key(String::from(value)) + } + + fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Error> { + match str::from_utf8(value) { + Ok(value) => self.set_key(String::from(value)), + Err(err) => Err(Error::Utf8(err)), + } + } + + fn serialize_unit(&mut self) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_unit_struct( + &mut self, name: &'static str) + -> Result<(), Error> { + self.set_key(name) + } + + fn serialize_unit_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result<(), Error> { + self.set_key(variant) + } + + fn serialize_newtype_struct( + &mut self, _name: &'static str, value: T) + -> Result<(), Error> + where T: Serialize + { + value.serialize(self) + } + + fn serialize_newtype_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_none(&mut self) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_some(&mut self, _value: T) -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_seq_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple(&mut self, _len: usize) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_struct( + &mut self, _name: &'static str, _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_struct_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_variant_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_map_key( + &mut self, _state: &mut (), _key: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_map_value( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_struct( + &mut self, _name: &'static str, _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_struct_elt( + &mut self, _state: &mut (), _key: &'static str, _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_key()) + } + + fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_struct_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_struct_variant_elt( + &mut self, _state: &mut (), _key: &'static str, _value: T) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } + + fn serialize_struct_variant_end( + &mut self, _state: ()) + -> Result<(), Error> { + Err(Error::unsupported_key()) + } +} + +impl Error { + fn unsupported_key() -> Self { + Error::Custom("unsupported key".into()) + } +} diff --git a/src/ser/mod.rs b/src/ser/mod.rs new file mode 100644 index 00000000..387766d5 --- /dev/null +++ b/src/ser/mod.rs @@ -0,0 +1,445 @@ +//! Serialization support for the `application/x-www-form-urlencoded` format. + +mod key; +mod pair; +mod value; + +use serde::ser; +use std::borrow::Cow; +use std::error; +use std::fmt; +use std::str; +use url::form_urlencoded; + +/// A serializer for the `application/x-www-form-urlencoded` format. +/// +/// * Supported top-level inputs are structs, maps and sequences of pairs, +/// with or without a given length. +/// +/// * Supported keys and values are integers, bytes (if convertible to strings), +/// unit structs and unit variants. +/// +/// * Newtype structs defer to their inner values. +pub struct Serializer(form_urlencoded::Serializer) + where T: form_urlencoded::Target; + +/// Errors returned during serializing to `application/x-www-form-urlencoded`. +#[derive(Clone, Debug)] +pub enum Error { + Custom(Cow<'static, str>), + InvalidValue(Cow<'static, str>), + Utf8(str::Utf8Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + Error::Custom(ref msg) => msg.fmt(f), + Error::InvalidValue(ref msg) => write!(f, "invalid value: {}", msg), + Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::Custom(ref msg) => msg, + Error::InvalidValue(ref msg) => msg, + Error::Utf8(ref err) => error::Error::description(err), + } + } + + /// The lower-level cause of this error, in the case of a `Utf8` error. + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Custom(_) | Error::InvalidValue(_) => None, + Error::Utf8(ref err) => Some(err), + } + } +} + +impl ser::Error for Error { + fn custom>(msg: T) -> Self { + Error::Custom(msg.into().into()) + } + + fn invalid_value(msg: &str) -> Self { + Error::InvalidValue(String::from(msg).into()) + } +} + +/// State used when serializing sequences. +pub struct SeqState(()); + +/// State used when serializing tuples. +pub struct TupleState(()); + +/// State used when serializing tuple structs. +pub struct TupleStructState(()); + +/// State used when serializing tuple variants. +pub struct TupleVariantState(()); + +/// State used when serializing maps. +pub struct MapState(Option>); + +/// State used when serializing structs. +pub struct StructState(()); + +/// State used when serializing struct variants. +pub struct StructVariantState(()); + +impl ser::Serializer for Serializer { + type Error = Error; + + /// State used when serializing sequences. + type SeqState = SeqState; + + /// State used when serializing tuples. + type TupleState = TupleState; + + /// State used when serializing tuple structs. + type TupleStructState = TupleStructState; + + /// State used when serializing tuple variants. + type TupleVariantState = TupleVariantState; + + /// State used when serializing maps. + type MapState = MapState; + + /// State used when serializing structs. + type StructState = StructState; + + /// State used when serializing struct variants. + type StructVariantState = StructVariantState; + + /// Returns an error. + fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_isize(&mut self, _v: isize) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_i8(&mut self, _v: i8) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_i16(&mut self, _v: i16) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_i32(&mut self, _v: i32) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_i64(&mut self, _v: i64) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_usize(&mut self, _v: usize) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_u8(&mut self, _v: u8) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_u16(&mut self, _v: u16) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_u32(&mut self, _v: u32) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_u64(&mut self, _v: u64) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_f32(&mut self, _v: f32) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_f64(&mut self, _v: f64) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_char(&mut self, _v: char) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_str(&mut self, _value: &str) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_bytes(&mut self, _value: &[u8]) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_unit(&mut self) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_unit_struct( + &mut self, _name: &'static str) + -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_unit_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str) + -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Serializes the inner value, ignoring the newtype name. + fn serialize_newtype_struct( + &mut self, _name: &'static str, value: T) + -> Result<(), Error> + where T: ser::Serialize + { + value.serialize(self) + } + + /// Returns an error. + fn serialize_newtype_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: ser::Serialize + { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_none(&mut self) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_some(&mut self, _value: T) -> Result<(), Error> + where T: ser::Serialize + { + Err(Error::top_level()) + } + + /// Begins to serialize a sequence, given length (if any) is ignored. + fn serialize_seq( + &mut self, _len: Option) + -> Result { + Ok(SeqState(())) + } + + /// Serializes a sequence element. + fn serialize_seq_elt( + &mut self, _state: &mut SeqState, value: T) + -> Result<(), Error> + where T: ser::Serialize + { + value.serialize(&mut pair::PairSerializer::new(&mut self.0)) + } + + /// Finishes serializing a sequence. + fn serialize_seq_end(&mut self, _state: SeqState) -> Result<(), Error> { + Ok(()) + } + + /// Begins to serialize a sequence, given length is ignored. + fn serialize_seq_fixed_size( + &mut self, _length: usize) + -> Result { + Ok(SeqState(())) + } + + /// Returns an error. + fn serialize_tuple(&mut self, _len: usize) -> Result { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_elt( + &mut self, _state: &mut TupleState, _value: T) + -> Result<(), Error> + where T: ser::Serialize + { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_end(&mut self, _state: TupleState) -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_struct( + &mut self, _name: &'static str, _len: usize) + -> Result { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_struct_elt( + &mut self, _state: &mut TupleStructState, _value: T) + -> Result<(), Error> + where T: ser::Serialize + { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_struct_end( + &mut self, _state: TupleStructState) + -> Result<(), Error> + { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_variant_elt( + &mut self, _state: &mut TupleVariantState, _value: T) + -> Result<(), Error> + where T: ser::Serialize + { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_variant_end( + &mut self, _state: TupleVariantState) + -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Begins to serialize a map, given length (if any) is ignored. + fn serialize_map( + &mut self, _len: Option) + -> Result { + Ok(MapState(None)) + } + + /// Serializes a map key. + fn serialize_map_key( + &mut self, state: &mut MapState, key: T) + -> Result<(), Error> + where T: ser::Serialize + { + key.serialize(&mut key::MapKeySerializer::new(&mut state.0)) + } + + /// Serializes a map value. + fn serialize_map_value( + &mut self, state: &mut MapState, value: T) + -> Result<(), Error> + where T: ser::Serialize + { + let mut value_serializer = + try!(value::ValueSerializer::new(&mut state.0, &mut self.0)); + value.serialize(&mut value_serializer) + } + + /// Finishes serializing a map. + fn serialize_map_end(&mut self, _state: MapState) -> Result<(), Error> { + Ok(()) + } + + /// Begins to serialize a struct, given length is ignored. + fn serialize_struct( + &mut self, _name: &'static str, _len: usize) + -> Result { + Ok(StructState(())) + } + + /// Serializes a struct element. + fn serialize_struct_elt( + &mut self, + _state: &mut StructState, + key: &'static str, + value: T) + -> Result<(), Error> + where T: ser::Serialize + { + let mut key = Some(key.into()); + let mut value_serializer = + value::ValueSerializer::new(&mut key, &mut self.0).unwrap(); + value.serialize(&mut value_serializer) + } + + /// Finishes serializing a struct. + fn serialize_struct_end(&mut self, _state: StructState) + -> Result<(), Error> { + Ok(()) + } + + /// Returns an error. + fn serialize_struct_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_struct_variant_elt( + &mut self, + _state: &mut StructVariantState, + _key: &'static str, + _value: T) + -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_struct_variant_end( + &mut self, _state: StructVariantState) + -> Result<(), Error> { + Err(Error::top_level()) + } +} + +impl Error { + fn top_level() -> Self { + Error::Custom( + "top-level serializer supports only maps and structs".into()) + } +} diff --git a/src/ser/pair.rs b/src/ser/pair.rs new file mode 100644 index 00000000..ae42db0d --- /dev/null +++ b/src/ser/pair.rs @@ -0,0 +1,330 @@ +use ser::{Error, key, value}; +use serde::{Serialize, Serializer}; +use std::borrow::Cow; +use url::form_urlencoded; + +pub struct PairSerializer<'target, Target>( + &'target mut form_urlencoded::Serializer) + where Target: 'target + form_urlencoded::Target; + +impl<'target, Target> PairSerializer<'target, Target> + where Target: 'target + form_urlencoded::Target +{ + pub fn new( + serializer: &'target mut form_urlencoded::Serializer) + -> Self { + PairSerializer(serializer) + } +} + +pub struct TupleState(Option>>); +pub struct TupleStructState(TupleState); + +impl<'target, Target> Serializer for PairSerializer<'target, Target> + where Target: 'target + form_urlencoded::Target +{ + type Error = Error; + type SeqState = (); + type TupleState = TupleState; + type TupleStructState = TupleStructState; + type TupleVariantState = (); + type MapState = (); + type StructState = (); + type StructVariantState = (); + + fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { + Err(Error::Custom("booleans are not supported values".into())) + } + + fn serialize_isize(&mut self, _v: isize) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i8(&mut self, _v: i8) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i16(&mut self, _v: i16) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i32(&mut self, _v: i32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i64(&mut self, _v: i64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_usize(&mut self, _v: usize) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u8(&mut self, _v: u8) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u16(&mut self, _v: u16) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u32(&mut self, _v: u32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u64(&mut self, _v: u64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_f32(&mut self, _v: f32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_f64(&mut self, _v: f64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_char(&mut self, _v: char) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_str(&mut self, _value: &str) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_bytes(&mut self, _value: &[u8]) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_unit(&mut self) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_unit_struct( + &mut self, _name: &'static str) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_unit_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_newtype_struct( + &mut self, _name: &'static str, value: T) + -> Result<(), Error> + where T: Serialize + { + value.serialize(self) + } + + fn serialize_newtype_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_none(&mut self) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_some(&mut self, _value: T) -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_seq(&mut self, _len: Option) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_seq_elt(&mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_seq_fixed_size(&mut self, _size: usize) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_tuple(&mut self, len: usize) -> Result { + if len == 2 { + Ok(TupleState(None)) + } else { + Err(Error::unsupported_pair()) + } + } + + fn serialize_tuple_elt( + &mut self, state: &mut TupleState, value: T) + -> Result<(), Error> + where T: Serialize + { + match state.0.take() { + None => { + let mut key = None; + { + let mut key_serializer = + key::MapKeySerializer::new(&mut key); + try!(value.serialize(&mut key_serializer)); + } + state.0 = Some(key); + Ok(()) + }, + Some(ref mut key) => { + { + let mut value_serializer = + value::ValueSerializer::new(key, &mut self.0).unwrap(); + try!(value.serialize(&mut value_serializer)); + } + state.0 = Some(None); + Ok(()) + } + } + } + + fn serialize_tuple_end(&mut self, _state: TupleState) -> Result<(), Error> { + Ok(()) + } + + fn serialize_tuple_struct( + &mut self, _name: &'static str, len: usize) + -> Result { + self.serialize_tuple(len).map(TupleStructState) + } + + fn serialize_tuple_struct_elt( + &mut self, state: &mut TupleStructState, value: T) + -> Result<(), Error> + where T: Serialize + { + self.serialize_tuple_elt(&mut state.0, value) + } + + fn serialize_tuple_struct_end( + &mut self, _state: TupleStructState) + -> Result<(), Error> { + Ok(()) + } + + fn serialize_tuple_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_tuple_variant_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_tuple_variant_end( + &mut self, _state: ()) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_map( + &mut self, _len: Option) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_map_key( + &mut self, _state: &mut (), _key: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_map_value( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_struct(&mut self, _name: &'static str, _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_struct_elt( + &mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_pair()) + } + + fn serialize_struct_end( + &mut self, _state: ()) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_struct_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + fn serialize_struct_variant_elt( + &mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_struct_variant_end( + &mut self, _state: ()) + -> Result<(), Error> { + Err(Error::unsupported_pair()) + } +} + +impl Error { + fn unsupported_pair() -> Self { + Error::Custom("unsupported pair".into()) + } +} diff --git a/src/ser/value.rs b/src/ser/value.rs new file mode 100644 index 00000000..39d3af09 --- /dev/null +++ b/src/ser/value.rs @@ -0,0 +1,322 @@ +use ser::Error; +use serde::{Serialize, Serializer}; +use std::borrow::Cow; +use std::str; +use url::form_urlencoded; + +pub struct ValueSerializer<'key, 'target, Target> + where Target: 'target + form_urlencoded::Target +{ + key: &'key mut Option>, + serializer: &'target mut form_urlencoded::Serializer +} + +impl<'key, 'target, Target> ValueSerializer<'key, 'target, Target> + where Target: 'target + form_urlencoded::Target +{ + pub fn new( + key: &'key mut Option>, + serializer: &'target mut form_urlencoded::Serializer) + -> Result { + if key.is_some() { + Ok(ValueSerializer { + key: key, + serializer: serializer, + }) + } else { + Err(Error::no_key()) + } + } + + fn append_pair(&mut self, value: &str) -> Result<(), Error> { + if let Some(key) = self.key.take() { + self.serializer.append_pair(&key, value); + Ok(()) + } else { + Err(Error::no_key()) + } + } +} + +impl<'key, 'target, Target> Serializer + for ValueSerializer<'key, 'target, Target> + where Target: 'target + form_urlencoded::Target +{ + type Error = Error; + type SeqState = (); + type TupleState = (); + type TupleStructState = (); + type TupleVariantState = (); + type MapState = (); + type StructState = (); + type StructVariantState = (); + + fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_isize(&mut self, v: isize) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_i8(&mut self, v: i8) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_i16(&mut self, v: i16) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_i32(&mut self, v: i32) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_i64(&mut self, v: i64) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_usize(&mut self, v: usize) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_u8(&mut self, v: u8) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_u16(&mut self, v: u16) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_u32(&mut self, v: u32) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_u64(&mut self, v: u64) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_f32(&mut self, v: f32) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_f64(&mut self, v: f64) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_char(&mut self, v: char) -> Result<(), Error> { + self.append_pair(&v.to_string()) + } + + fn serialize_str(&mut self, value: &str) -> Result<(), Error> { + self.append_pair(value) + } + + fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Error> { + match str::from_utf8(value) { + Ok(value) => self.append_pair(value), + Err(err) => Err(Error::Utf8(err)), + } + } + + fn serialize_unit(&mut self) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_unit_struct( + &mut self, name: &'static str) + -> Result<(), Error> { + self.append_pair(name) + } + + fn serialize_unit_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result<(), Error> { + self.append_pair(variant) + } + + fn serialize_newtype_struct( + &mut self, _name: &'static str, value: T) + -> Result<(), Error> + where T: Serialize + { + value.serialize(self) + } + + fn serialize_newtype_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_none(&mut self) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_some(&mut self, _value: T) -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_seq_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple(&mut self, _len: usize) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_struct( + &mut self, _name: &'static str, _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_struct_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_variant_elt( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_map_key( + &mut self, _state: &mut (), _key: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_map_value( + &mut self, _state: &mut (), _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_struct( + &mut self, _name: &'static str, _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_struct_elt( + &mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize + { + Err(Error::unsupported_value()) + } + + fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_struct_variant( + &mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } + fn serialize_struct_variant_elt( + &mut self, _state: &mut (), _key: &'static str, _value: T) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } + + fn serialize_struct_variant_end( + &mut self, _state: ()) + -> Result<(), Error> { + Err(Error::unsupported_value()) + } +} + +impl Error { + fn no_key() -> Self { + Error::Custom( + "tried to serialize a value before serializing key".into()) + } + + fn unsupported_value() -> Self { + Error::Custom("unsupported value".into()) + } +} From 6a21acd17261baa1afe8b73ab99bd1b325a3a5c1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 18:36:15 +0200 Subject: [PATCH 02/95] Make Serializer borrow its inner url-encoded serializer While at it, create Serializer::new to actually instantiate it. --- src/ser/mod.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 387766d5..32c1bfd2 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -9,7 +9,8 @@ use std::borrow::Cow; use std::error; use std::fmt; use std::str; -use url::form_urlencoded; +use url::form_urlencoded::Serializer as UrlEncodedSerializer; +use url::form_urlencoded::Target as UrlEncodedTarget; /// A serializer for the `application/x-www-form-urlencoded` format. /// @@ -20,8 +21,15 @@ use url::form_urlencoded; /// unit structs and unit variants. /// /// * Newtype structs defer to their inner values. -pub struct Serializer(form_urlencoded::Serializer) - where T: form_urlencoded::Target; +pub struct Serializer<'output, T: 'output>(&'output mut UrlEncodedSerializer) + where T: UrlEncodedTarget; + +impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { + /// Returns a new `Serializer`. + pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { + Serializer(urlencoder) + } +} /// Errors returned during serializing to `application/x-www-form-urlencoded`. #[derive(Clone, Debug)] @@ -90,7 +98,9 @@ pub struct StructState(()); /// State used when serializing struct variants. pub struct StructVariantState(()); -impl ser::Serializer for Serializer { +impl<'output, Target> ser::Serializer for Serializer<'output, Target> + where Target: 'output + UrlEncodedTarget +{ type Error = Error; /// State used when serializing sequences. @@ -263,7 +273,7 @@ impl ser::Serializer for Serializer { -> Result<(), Error> where T: ser::Serialize { - value.serialize(&mut pair::PairSerializer::new(&mut self.0)) + value.serialize(&mut pair::PairSerializer::new(self.0)) } /// Finishes serializing a sequence. @@ -371,7 +381,7 @@ impl ser::Serializer for Serializer { where T: ser::Serialize { let mut value_serializer = - try!(value::ValueSerializer::new(&mut state.0, &mut self.0)); + try!(value::ValueSerializer::new(&mut state.0, self.0)); value.serialize(&mut value_serializer) } @@ -398,7 +408,7 @@ impl ser::Serializer for Serializer { { let mut key = Some(key.into()); let mut value_serializer = - value::ValueSerializer::new(&mut key, &mut self.0).unwrap(); + value::ValueSerializer::new(&mut key, self.0).unwrap(); value.serialize(&mut value_serializer) } From b0794d23e3a0a8d134de05c431ec8fbd905425c7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 18:43:22 +0200 Subject: [PATCH 03/95] Remove the T parameter from Deserializer No idea how that ended up there. --- src/de.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/de.rs b/src/de.rs index ec84ff22..8925f529 100644 --- a/src/de.rs +++ b/src/de.rs @@ -3,8 +3,7 @@ use serde::de; use serde::de::value::MapDeserializer; use std::borrow::Cow; -use std::marker::PhantomData; -use url::form_urlencoded::Parse; +use url::form_urlencoded::Parse as UrlEncodedParse; pub use serde::de::value::Error; @@ -17,12 +16,17 @@ pub use serde::de::value::Error; /// /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. -pub struct Deserializer<'a, T> { - deserializer: MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>, - marker: PhantomData, +pub struct Deserializer<'a>( + MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>); + +impl<'a> Deserializer<'a> { + /// Returns a new `Deserializer`. + pub fn new(parser: UrlEncodedParse<'a>) -> Self { + Deserializer(MapDeserializer::unbounded(parser)) + } } -impl<'a, T> de::Deserializer for Deserializer<'a, T> +impl<'a> de::Deserializer for Deserializer<'a> { type Error = Error; @@ -39,7 +43,7 @@ impl<'a, T> de::Deserializer for Deserializer<'a, T> -> Result where V: de::Visitor, { - visitor.visit_map(&mut self.deserializer) + visitor.visit_map(&mut self.0) } fn deserialize_seq( @@ -47,7 +51,7 @@ impl<'a, T> de::Deserializer for Deserializer<'a, T> -> Result where V: de::Visitor, { - visitor.visit_seq(&mut self.deserializer) + visitor.visit_seq(&mut self.0) } fn deserialize_seq_fixed_size( @@ -55,7 +59,7 @@ impl<'a, T> de::Deserializer for Deserializer<'a, T> -> Result where V: de::Visitor { - visitor.visit_seq(&mut self.deserializer) + visitor.visit_seq(&mut self.0) } forward_to_deserialize! { From 967549d85996443bee850c492e23cf40fb889ec4 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 18:49:29 +0200 Subject: [PATCH 04/95] Add convenience functions (fixes #2) --- src/de.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 ++-- src/ser/mod.rs | 25 ++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/de.rs b/src/de.rs index 8925f529..695547f4 100644 --- a/src/de.rs +++ b/src/de.rs @@ -4,9 +4,48 @@ use serde::de; use serde::de::value::MapDeserializer; use std::borrow::Cow; use url::form_urlencoded::Parse as UrlEncodedParse; +use url::form_urlencoded::parse; pub use serde::de::value::Error; +/// Deserializes a `application/x-wwww-url-encoded` value from a `&[u8]`. +/// +/// ``` +/// let meal = vec![ +/// ("bread".to_owned(), "baguette".to_owned()), +/// ("cheese".to_owned(), "comté".to_owned()), +/// ("meat".to_owned(), "ham".to_owned()), +/// ("fat".to_owned(), "butter".to_owned()), +/// ]; +/// +/// assert_eq!( +/// serde_urlencoded::from_bytes::>( +/// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), +/// Ok(meal)); +/// ``` +pub fn from_bytes(input: &[u8]) -> Result { + T::deserialize(&mut Deserializer::new(parse(input))) +} + +/// Deserializes a `application/x-wwww-url-encoded` value from a `&str`. +/// +/// ``` +/// let meal = vec![ +/// ("bread".to_owned(), "baguette".to_owned()), +/// ("cheese".to_owned(), "comté".to_owned()), +/// ("meat".to_owned(), "ham".to_owned()), +/// ("fat".to_owned(), "butter".to_owned()), +/// ]; +/// +/// assert_eq!( +/// serde_urlencoded::from_str::>( +/// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), +/// Ok(meal)); +/// ``` +pub fn from_str(input: &str) -> Result { + from_bytes(input.as_bytes()) +} + /// A deserializer for the `application/x-www-form-urlencoded` format. /// /// * Supported top-level outputs are structs, maps and sequences of pairs, diff --git a/src/lib.rs b/src/lib.rs index 95a0ad60..bacb67f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,5 +7,5 @@ extern crate url; pub mod de; pub mod ser; -pub use de::Deserializer; -pub use ser::Serializer; +pub use de::{Deserializer, from_bytes, from_str}; +pub use ser::{Serializer, to_string}; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 32c1bfd2..1c030c1c 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -12,6 +12,29 @@ use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; +/// Serializes a value into a `application/x-wwww-url-encoded` `String` buffer. +/// +/// ``` +/// let meal = &[ +/// ("bread", "baguette"), +/// ("cheese", "comté"), +/// ("meat", "ham"), +/// ("fat", "butter"), +/// ]; +/// +/// assert_eq!( +/// serde_urlencoded::to_string(meal), +/// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); +/// ``` +pub fn to_string(input: &T) -> Result { + let mut output = String::new(); + { + let mut urlencoder = UrlEncodedSerializer::new(&mut output); + try!(input.serialize(&mut Serializer::new(&mut urlencoder))); + } + Ok(output) +} + /// A serializer for the `application/x-www-form-urlencoded` format. /// /// * Supported top-level inputs are structs, maps and sequences of pairs, @@ -32,7 +55,7 @@ impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { } /// Errors returned during serializing to `application/x-www-form-urlencoded`. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum Error { Custom(Cow<'static, str>), InvalidValue(Cow<'static, str>), From 56ee81e39819e1743d04f881b59279a979f1763d Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 18:50:46 +0200 Subject: [PATCH 05/95] Update to 0.2.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a5098d9b..98a8992b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.1.0" +version = "0.2.0" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 042a5eb0779dc38d3db3166ba997d4662ed6f5e7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 11 Sep 2016 21:29:47 +0200 Subject: [PATCH 06/95] Fix number version in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c9fe8fe..0fa1aa3c 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate works with Cargo and can be found on ```toml [dependencies] -serde_urlencoded = "0.1" +serde_urlencoded = "0.2" ``` [crates.io]: https://crates.io/crates/serde_urlencoded From f639279e3ea7c87ed418bb46e0f65f2017f6c19f Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Thu, 15 Sep 2016 00:24:52 +0200 Subject: [PATCH 07/95] Add support for option parameters --- src/ser/value.rs | 10 +++++++--- tests/test_serialize.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 tests/test_serialize.rs diff --git a/src/ser/value.rs b/src/ser/value.rs index 39d3af09..7a2ac42e 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -158,13 +158,17 @@ impl<'key, 'target, Target> Serializer } fn serialize_none(&mut self) -> Result<(), Error> { - Err(Error::unsupported_value()) + if let Some(_) = self.key.take() { + Ok(()) + } else { + Err(Error::no_key()) + } } - fn serialize_some(&mut self, _value: T) -> Result<(), Error> + fn serialize_some(&mut self, value: T) -> Result<(), Error> where T: Serialize { - Err(Error::unsupported_value()) + value.serialize(self) } fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs new file mode 100644 index 00000000..20592fcc --- /dev/null +++ b/tests/test_serialize.rs @@ -0,0 +1,27 @@ +extern crate serde_urlencoded; + +#[test] +fn serialize_option_map_int() { + let params = &[ + ("first", Some(23)), + ("middle", None), + ("last", Some(42)), + ]; + + assert_eq!( + serde_urlencoded::to_string(params), + Ok("first=23&last=42".to_owned())); +} + +#[test] +fn serialize_option_map_string() { + let params = &[ + ("first", Some("hello")), + ("middle", None), + ("last", Some("world")), + ]; + + assert_eq!( + serde_urlencoded::to_string(params), + Ok("first=hello&last=world".to_owned())); +} From c75cccbb0395060a1e2c11272a64e9fb09697cc0 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 19 Sep 2016 11:22:15 +0200 Subject: [PATCH 08/95] Bump version to 0.2.1 --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 98a8992b..6c5ceba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.2.0" +version = "0.2.1" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" diff --git a/README.md b/README.md index 0fa1aa3c..2f0f1782 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate works with Cargo and can be found on ```toml [dependencies] -serde_urlencoded = "0.2" +serde_urlencoded = "0.2.1" ``` [crates.io]: https://crates.io/crates/serde_urlencoded From f553c4e08f11c18ef03fdacfcfaaea4771a13b4e Mon Sep 17 00:00:00 2001 From: Matthias Endler Date: Wed, 21 Sep 2016 22:55:36 +0200 Subject: [PATCH 09/95] Add support for boolean values --- src/ser/value.rs | 4 ++-- tests/test_serialize.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/ser/value.rs b/src/ser/value.rs index 7a2ac42e..d0172424 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -51,8 +51,8 @@ impl<'key, 'target, Target> Serializer type StructState = (); type StructVariantState = (); - fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { - Err(Error::unsupported_value()) + fn serialize_bool(&mut self, v: bool) -> Result<(), Error> { + self.append_pair(if v { "true" } else { "false" }) } fn serialize_isize(&mut self, v: isize) -> Result<(), Error> { diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 20592fcc..b401ef94 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -25,3 +25,27 @@ fn serialize_option_map_string() { serde_urlencoded::to_string(params), Ok("first=hello&last=world".to_owned())); } + +#[test] +fn serialize_option_map_bool() { + let params = &[ + ("one", Some(true)), + ("two", Some(false)) + ]; + + assert_eq!( + serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned())); +} + +#[test] +fn serialize_map_bool() { + let params = &[ + ("one", true), + ("two", false) + ]; + + assert_eq!( + serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned())); +} From 7e09a773cd10461fc0d18ca15475fef62368d293 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 22 Sep 2016 14:39:38 +0200 Subject: [PATCH 10/95] Bump version to 0.2.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6c5ceba6..9a1cf6e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.2.1" +version = "0.2.2" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 39f7d33b0b3e25da392257311ee071bcf3857d25 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 23 Oct 2016 11:55:16 +0200 Subject: [PATCH 11/95] Use opaque structs instead of opaque tuples Opaque struct tuples leak their arity. --- src/de.rs | 14 ++++++++------ src/ser/mod.rs | 51 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/de.rs b/src/de.rs index 695547f4..0f3cb783 100644 --- a/src/de.rs +++ b/src/de.rs @@ -55,13 +55,15 @@ pub fn from_str(input: &str) -> Result { /// /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. -pub struct Deserializer<'a>( - MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>); +pub struct Deserializer<'a> { + inner: + MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>, +} impl<'a> Deserializer<'a> { /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'a>) -> Self { - Deserializer(MapDeserializer::unbounded(parser)) + Deserializer { inner: MapDeserializer::unbounded(parser) } } } @@ -82,7 +84,7 @@ impl<'a> de::Deserializer for Deserializer<'a> -> Result where V: de::Visitor, { - visitor.visit_map(&mut self.0) + visitor.visit_map(&mut self.inner) } fn deserialize_seq( @@ -90,7 +92,7 @@ impl<'a> de::Deserializer for Deserializer<'a> -> Result where V: de::Visitor, { - visitor.visit_seq(&mut self.0) + visitor.visit_seq(&mut self.inner) } fn deserialize_seq_fixed_size( @@ -98,7 +100,7 @@ impl<'a> de::Deserializer for Deserializer<'a> -> Result where V: de::Visitor { - visitor.visit_seq(&mut self.0) + visitor.visit_seq(&mut self.inner) } forward_to_deserialize! { diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 1c030c1c..c1da3b12 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -44,13 +44,14 @@ pub fn to_string(input: &T) -> Result { /// unit structs and unit variants. /// /// * Newtype structs defer to their inner values. -pub struct Serializer<'output, T: 'output>(&'output mut UrlEncodedSerializer) - where T: UrlEncodedTarget; +pub struct Serializer<'output, T: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer +} impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { /// Returns a new `Serializer`. pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { - Serializer(urlencoder) + Serializer { urlencoder: urlencoder } } } @@ -101,25 +102,39 @@ impl ser::Error for Error { } /// State used when serializing sequences. -pub struct SeqState(()); +pub struct SeqState { + _state: (), +} /// State used when serializing tuples. -pub struct TupleState(()); +pub struct TupleState { + _state: (), +} /// State used when serializing tuple structs. -pub struct TupleStructState(()); +pub struct TupleStructState { + _state: (), +} /// State used when serializing tuple variants. -pub struct TupleVariantState(()); +pub struct TupleVariantState { + _state: (), +} /// State used when serializing maps. -pub struct MapState(Option>); +pub struct MapState { + key: Option> +} /// State used when serializing structs. -pub struct StructState(()); +pub struct StructState { + _state: (), +} /// State used when serializing struct variants. -pub struct StructVariantState(()); +pub struct StructVariantState { + _state: (), +} impl<'output, Target> ser::Serializer for Serializer<'output, Target> where Target: 'output + UrlEncodedTarget @@ -287,7 +302,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_seq( &mut self, _len: Option) -> Result { - Ok(SeqState(())) + Ok(SeqState { _state: () }) } /// Serializes a sequence element. @@ -296,7 +311,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> -> Result<(), Error> where T: ser::Serialize { - value.serialize(&mut pair::PairSerializer::new(self.0)) + value.serialize(&mut pair::PairSerializer::new(self.urlencoder)) } /// Finishes serializing a sequence. @@ -308,7 +323,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_seq_fixed_size( &mut self, _length: usize) -> Result { - Ok(SeqState(())) + Ok(SeqState { _state: () }) } /// Returns an error. @@ -385,7 +400,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_map( &mut self, _len: Option) -> Result { - Ok(MapState(None)) + Ok(MapState { key: None }) } /// Serializes a map key. @@ -394,7 +409,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> -> Result<(), Error> where T: ser::Serialize { - key.serialize(&mut key::MapKeySerializer::new(&mut state.0)) + key.serialize(&mut key::MapKeySerializer::new(&mut state.key)) } /// Serializes a map value. @@ -404,7 +419,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> where T: ser::Serialize { let mut value_serializer = - try!(value::ValueSerializer::new(&mut state.0, self.0)); + try!(value::ValueSerializer::new(&mut state.key, self.urlencoder)); value.serialize(&mut value_serializer) } @@ -417,7 +432,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_struct( &mut self, _name: &'static str, _len: usize) -> Result { - Ok(StructState(())) + Ok(StructState { _state: () }) } /// Serializes a struct element. @@ -431,7 +446,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> { let mut key = Some(key.into()); let mut value_serializer = - value::ValueSerializer::new(&mut key, self.0).unwrap(); + value::ValueSerializer::new(&mut key, self.urlencoder).unwrap(); value.serialize(&mut value_serializer) } From f9c64eb16cf75631920533d9972031e6dfcb5a09 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 23 Oct 2016 11:56:27 +0200 Subject: [PATCH 12/95] Support serializing top-level Option values --- src/ser/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index c1da3b12..f04c9567 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -288,14 +288,14 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> /// Returns an error. fn serialize_none(&mut self) -> Result<(), Error> { - Err(Error::top_level()) + Ok(()) } /// Returns an error. - fn serialize_some(&mut self, _value: T) -> Result<(), Error> + fn serialize_some(&mut self, value: T) -> Result<(), Error> where T: ser::Serialize { - Err(Error::top_level()) + value.serialize(self) } /// Begins to serialize a sequence, given length (if any) is ignored. From 5202ee622b573eaa3870da4df75638f89cda3449 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 23 Oct 2016 12:13:09 +0200 Subject: [PATCH 13/95] Support Option values in the sequence serializer This allows us to serialize sequences of Option<(K, V)> values. --- src/ser/pair.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ser/pair.rs b/src/ser/pair.rs index ae42db0d..6dfed3d9 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -136,13 +136,13 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> } fn serialize_none(&mut self) -> Result<(), Error> { - Err(Error::unsupported_pair()) + Ok(()) } - fn serialize_some(&mut self, _value: T) -> Result<(), Error> + fn serialize_some(&mut self, value: T) -> Result<(), Error> where T: Serialize { - Err(Error::unsupported_pair()) + value.serialize(self) } fn serialize_seq(&mut self, _len: Option) From 9aefb1c02d8cb5746f07dc6ac461ce8eedced5e3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 23 Oct 2016 12:24:46 +0200 Subject: [PATCH 14/95] Bump version to 0.3.0 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9a1cf6e1..95845cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "serde_urlencoded" -version = "0.2.2" +version = "0.3.0" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" -documentation = "https://docs.rs/crate/serde_urlencoded" +documentation = "https://docs.rs/serde_urlencoded" description = "`x-www-form-urlencoded` meets Serde" keywords = ["serde", "serialization", "urlencoded"] From 8e5cf19e0740afabf8f8254441e88c756240fcb1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 27 Jan 2017 22:56:04 +0100 Subject: [PATCH 15/95] Reformat with rustfmt --- rustfmt.toml | 7 ++ src/de.rs | 38 +++---- src/ser/key.rs | 166 ++++++++++++++-------------- src/ser/mod.rs | 234 ++++++++++++++++++++-------------------- src/ser/pair.rs | 202 +++++++++++++++++----------------- src/ser/value.rs | 183 ++++++++++++++++--------------- tests/test_serialize.rs | 43 +++----- 7 files changed, 439 insertions(+), 434 deletions(-) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..70b05dfe --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +match_block_trailing_comma = true +max_width = 80 +newline_style = "Unix" +reorder_imported_names = true +reorder_imports = true +use_try_shorthand = true +where_trailing_comma = true diff --git a/src/de.rs b/src/de.rs index 0f3cb783..42c1f043 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,13 +1,13 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. use serde::de; + +pub use serde::de::value::Error; use serde::de::value::MapDeserializer; use std::borrow::Cow; use url::form_urlencoded::Parse as UrlEncodedParse; use url::form_urlencoded::parse; -pub use serde::de::value::Error; - /// Deserializes a `application/x-wwww-url-encoded` value from a `&[u8]`. /// /// ``` @@ -56,8 +56,10 @@ pub fn from_str(input: &str) -> Result { /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'a> { - inner: - MapDeserializer, Cow<'a, str>, Cow<'a, str>, Error>, + inner: MapDeserializer, + Cow<'a, str>, + Cow<'a, str>, + Error>, } impl<'a> Deserializer<'a> { @@ -67,38 +69,36 @@ impl<'a> Deserializer<'a> { } } -impl<'a> de::Deserializer for Deserializer<'a> -{ +impl<'a> de::Deserializer for Deserializer<'a> { type Error = Error; - fn deserialize( - &mut self, visitor: V) - -> Result + fn deserialize(&mut self, visitor: V) -> Result where V: de::Visitor, { self.deserialize_map(visitor) } - fn deserialize_map( - &mut self, mut visitor: V) - -> Result + fn deserialize_map(&mut self, + mut visitor: V) + -> Result where V: de::Visitor, { visitor.visit_map(&mut self.inner) } - fn deserialize_seq( - &mut self, mut visitor: V) - -> Result + fn deserialize_seq(&mut self, + mut visitor: V) + -> Result where V: de::Visitor, { visitor.visit_seq(&mut self.inner) } - fn deserialize_seq_fixed_size( - &mut self, _len: usize, mut visitor: V) - -> Result - where V: de::Visitor + fn deserialize_seq_fixed_size(&mut self, + _len: usize, + mut visitor: V) + -> Result + where V: de::Visitor, { visitor.visit_seq(&mut self.inner) } diff --git a/src/ser/key.rs b/src/ser/key.rs index a26c5638..0e5f7a67 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -1,5 +1,6 @@ -use serde::{Serialize, Serializer}; + use ser::Error; +use serde::{Serialize, Serializer}; use std::borrow::Cow; use std::str; @@ -11,7 +12,7 @@ impl<'key> MapKeySerializer<'key> { } fn set_key(&mut self, key: T) -> Result<(), Error> - where T: Into> + where T: Into>, { *self.0 = Some(key.into()); Ok(()) @@ -99,37 +100,36 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_unit_struct( - &mut self, name: &'static str) - -> Result<(), Error> { + fn serialize_unit_struct(&mut self, + name: &'static str) + -> Result<(), Error> { self.set_key(name) } - fn serialize_unit_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - variant: &'static str) - -> Result<(), Error> { + fn serialize_unit_variant(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result<(), Error> { self.set_key(variant) } - fn serialize_newtype_struct( - &mut self, _name: &'static str, value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_struct(&mut self, + _name: &'static str, + value: T) + -> Result<(), Error> + where T: Serialize, { value.serialize(self) } - fn serialize_newtype_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -139,7 +139,7 @@ impl<'key> Serializer for MapKeySerializer<'key> { } fn serialize_some(&mut self, _value: T) -> Result<(), Error> - where T: Serialize + where T: Serialize, { Err(Error::unsupported_key()) } @@ -148,10 +148,11 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_seq_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_seq_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -168,10 +169,11 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_tuple_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -180,16 +182,18 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_tuple_struct( - &mut self, _name: &'static str, _len: usize) - -> Result<(), Error> { + fn serialize_tuple_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_key()) } - fn serialize_tuple_struct_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_struct_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -198,20 +202,20 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_tuple_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_tuple_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_key()) } - fn serialize_tuple_variant_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_variant_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -224,18 +228,20 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_map_key( - &mut self, _state: &mut (), _key: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_key(&mut self, + _state: &mut (), + _key: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } - fn serialize_map_value( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_value(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -244,16 +250,19 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_struct( - &mut self, _name: &'static str, _len: usize) - -> Result<(), Error> { + fn serialize_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_key()) } - fn serialize_struct_elt( - &mut self, _state: &mut (), _key: &'static str, _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_struct_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_key()) } @@ -262,25 +271,26 @@ impl<'key> Serializer for MapKeySerializer<'key> { Err(Error::unsupported_key()) } - fn serialize_struct_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_struct_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_key()) } - fn serialize_struct_variant_elt( - &mut self, _state: &mut (), _key: &'static str, _value: T) - -> Result<(), Error> { + fn serialize_struct_variant_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> { Err(Error::unsupported_key()) } - fn serialize_struct_variant_end( - &mut self, _state: ()) - -> Result<(), Error> { + fn serialize_struct_variant_end(&mut self, + _state: ()) + -> Result<(), Error> { Err(Error::unsupported_key()) } } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index f04c9567..00c0540a 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -30,7 +30,7 @@ pub fn to_string(input: &T) -> Result { let mut output = String::new(); { let mut urlencoder = UrlEncodedSerializer::new(&mut output); - try!(input.serialize(&mut Serializer::new(&mut urlencoder))); + input.serialize(&mut Serializer::new(&mut urlencoder))?; } Ok(output) } @@ -45,7 +45,7 @@ pub fn to_string(input: &T) -> Result { /// /// * Newtype structs defer to their inner values. pub struct Serializer<'output, T: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer + urlencoder: &'output mut UrlEncodedSerializer, } impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { @@ -85,7 +85,8 @@ impl error::Error for Error { /// The lower-level cause of this error, in the case of a `Utf8` error. fn cause(&self) -> Option<&error::Error> { match *self { - Error::Custom(_) | Error::InvalidValue(_) => None, + Error::Custom(_) | + Error::InvalidValue(_) => None, Error::Utf8(ref err) => Some(err), } } @@ -123,7 +124,7 @@ pub struct TupleVariantState { /// State used when serializing maps. pub struct MapState { - key: Option> + key: Option>, } /// State used when serializing structs. @@ -137,7 +138,7 @@ pub struct StructVariantState { } impl<'output, Target> ser::Serializer for Serializer<'output, Target> - where Target: 'output + UrlEncodedTarget + where Target: 'output + UrlEncodedTarget, { type Error = Error; @@ -248,40 +249,39 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Returns an error. - fn serialize_unit_struct( - &mut self, _name: &'static str) - -> Result<(), Error> { + fn serialize_unit_struct(&mut self, + _name: &'static str) + -> Result<(), Error> { Err(Error::top_level()) } /// Returns an error. - fn serialize_unit_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str) - -> Result<(), Error> { + fn serialize_unit_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str) + -> Result<(), Error> { Err(Error::top_level()) } /// Serializes the inner value, ignoring the newtype name. - fn serialize_newtype_struct( - &mut self, _name: &'static str, value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_newtype_struct(&mut self, + _name: &'static str, + value: T) + -> Result<(), Error> + where T: ser::Serialize, { value.serialize(self) } /// Returns an error. - fn serialize_newtype_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_newtype_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: ser::Serialize, { Err(Error::top_level()) } @@ -293,23 +293,24 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> /// Returns an error. fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: ser::Serialize + where T: ser::Serialize, { value.serialize(self) } /// Begins to serialize a sequence, given length (if any) is ignored. - fn serialize_seq( - &mut self, _len: Option) - -> Result { + fn serialize_seq(&mut self, + _len: Option) + -> Result { Ok(SeqState { _state: () }) } /// Serializes a sequence element. - fn serialize_seq_elt( - &mut self, _state: &mut SeqState, value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_seq_elt(&mut self, + _state: &mut SeqState, + value: T) + -> Result<(), Error> + where T: ser::Serialize, { value.serialize(&mut pair::PairSerializer::new(self.urlencoder)) } @@ -320,9 +321,9 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Begins to serialize a sequence, given length is ignored. - fn serialize_seq_fixed_size( - &mut self, _length: usize) - -> Result { + fn serialize_seq_fixed_size(&mut self, + _length: usize) + -> Result { Ok(SeqState { _state: () }) } @@ -332,10 +333,11 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Returns an error. - fn serialize_tuple_elt( - &mut self, _state: &mut TupleState, _value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_tuple_elt(&mut self, + _state: &mut TupleState, + _value: T) + -> Result<(), Error> + where T: ser::Serialize, { Err(Error::top_level()) } @@ -346,80 +348,83 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Returns an error. - fn serialize_tuple_struct( - &mut self, _name: &'static str, _len: usize) - -> Result { + fn serialize_tuple_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_struct_elt( - &mut self, _state: &mut TupleStructState, _value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_tuple_struct_elt(&mut self, + _state: &mut TupleStructState, + _value: T) + -> Result<(), Error> + where T: ser::Serialize, { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_struct_end( - &mut self, _state: TupleStructState) - -> Result<(), Error> + fn serialize_tuple_struct_end(&mut self, + _state: TupleStructState) + -> Result<(), Error> { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(Error::top_level()) + } + + /// Returns an error. + fn serialize_tuple_variant_elt(&mut self, + _state: &mut TupleVariantState, + _value: T) + -> Result<(), Error> + where T: ser::Serialize, { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_variant_elt( - &mut self, _state: &mut TupleVariantState, _value: T) - -> Result<(), Error> - where T: ser::Serialize - { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_variant_end( - &mut self, _state: TupleVariantState) - -> Result<(), Error> { + fn serialize_tuple_variant_end(&mut self, + _state: TupleVariantState) + -> Result<(), Error> { Err(Error::top_level()) } /// Begins to serialize a map, given length (if any) is ignored. - fn serialize_map( - &mut self, _len: Option) - -> Result { + fn serialize_map(&mut self, + _len: Option) + -> Result { Ok(MapState { key: None }) } /// Serializes a map key. - fn serialize_map_key( - &mut self, state: &mut MapState, key: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_map_key(&mut self, + state: &mut MapState, + key: T) + -> Result<(), Error> + where T: ser::Serialize, { key.serialize(&mut key::MapKeySerializer::new(&mut state.key)) } /// Serializes a map value. - fn serialize_map_value( - &mut self, state: &mut MapState, value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_map_value(&mut self, + state: &mut MapState, + value: T) + -> Result<(), Error> + where T: ser::Serialize, { let mut value_serializer = - try!(value::ValueSerializer::new(&mut state.key, self.urlencoder)); + value::ValueSerializer::new(&mut state.key, self.urlencoder)?; value.serialize(&mut value_serializer) } @@ -429,20 +434,20 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Begins to serialize a struct, given length is ignored. - fn serialize_struct( - &mut self, _name: &'static str, _len: usize) - -> Result { + fn serialize_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result { Ok(StructState { _state: () }) } /// Serializes a struct element. - fn serialize_struct_elt( - &mut self, - _state: &mut StructState, - key: &'static str, - value: T) - -> Result<(), Error> - where T: ser::Serialize + fn serialize_struct_elt(&mut self, + _state: &mut StructState, + key: &'static str, + value: T) + -> Result<(), Error> + where T: ser::Serialize, { let mut key = Some(key.into()); let mut value_serializer = @@ -451,43 +456,42 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Finishes serializing a struct. - fn serialize_struct_end(&mut self, _state: StructState) + fn serialize_struct_end(&mut self, + _state: StructState) -> Result<(), Error> { Ok(()) } /// Returns an error. - fn serialize_struct_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_struct_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_struct_variant_elt( - &mut self, - _state: &mut StructVariantState, - _key: &'static str, - _value: T) - -> Result<(), Error> { + fn serialize_struct_variant_elt(&mut self, + _state: &mut StructVariantState, + _key: &'static str, + _value: T) + -> Result<(), Error> { Err(Error::top_level()) } /// Returns an error. - fn serialize_struct_variant_end( - &mut self, _state: StructVariantState) - -> Result<(), Error> { + fn serialize_struct_variant_end(&mut self, + _state: StructVariantState) + -> Result<(), Error> { Err(Error::top_level()) } } impl Error { fn top_level() -> Self { - Error::Custom( - "top-level serializer supports only maps and structs".into()) + Error::Custom("top-level serializer supports only maps and structs" + .into()) } } diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 6dfed3d9..36eda51a 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -8,11 +8,10 @@ pub struct PairSerializer<'target, Target>( where Target: 'target + form_urlencoded::Target; impl<'target, Target> PairSerializer<'target, Target> - where Target: 'target + form_urlencoded::Target + where Target: 'target + form_urlencoded::Target, { - pub fn new( - serializer: &'target mut form_urlencoded::Serializer) - -> Self { + pub fn new(serializer: &'target mut form_urlencoded::Serializer) + -> Self { PairSerializer(serializer) } } @@ -21,7 +20,7 @@ pub struct TupleState(Option>>); pub struct TupleStructState(TupleState); impl<'target, Target> Serializer for PairSerializer<'target, Target> - where Target: 'target + form_urlencoded::Target + where Target: 'target + form_urlencoded::Target, { type Error = Error; type SeqState = (); @@ -100,37 +99,36 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_unit_struct( - &mut self, _name: &'static str) - -> Result<(), Error> { + fn serialize_unit_struct(&mut self, + _name: &'static str) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_unit_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str) - -> Result<(), Error> { + fn serialize_unit_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_newtype_struct( - &mut self, _name: &'static str, value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_struct(&mut self, + _name: &'static str, + value: T) + -> Result<(), Error> + where T: Serialize, { value.serialize(self) } - fn serialize_newtype_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_pair()) } @@ -140,19 +138,20 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> } fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: Serialize + where T: Serialize, { value.serialize(self) } - fn serialize_seq(&mut self, _len: Option) - -> Result<(), Error> { + fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_seq_elt(&mut self, _state: &mut (), _value: T) + fn serialize_seq_elt(&mut self, + _state: &mut (), + _value: T) -> Result<(), Error> - where T: Serialize + where T: Serialize, { Err(Error::unsupported_pair()) } @@ -161,8 +160,7 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_seq_fixed_size(&mut self, _size: usize) - -> Result<(), Error> { + fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { Err(Error::unsupported_pair()) } @@ -174,10 +172,11 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> } } - fn serialize_tuple_elt( - &mut self, state: &mut TupleState, value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_elt(&mut self, + state: &mut TupleState, + value: T) + -> Result<(), Error> + where T: Serialize, { match state.0.take() { None => { @@ -185,7 +184,7 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> { let mut key_serializer = key::MapKeySerializer::new(&mut key); - try!(value.serialize(&mut key_serializer)); + value.serialize(&mut key_serializer)?; } state.0 = Some(key); Ok(()) @@ -194,11 +193,11 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> { let mut value_serializer = value::ValueSerializer::new(key, &mut self.0).unwrap(); - try!(value.serialize(&mut value_serializer)); + value.serialize(&mut value_serializer)?; } state.0 = Some(None); Ok(()) - } + }, } } @@ -206,68 +205,68 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> Ok(()) } - fn serialize_tuple_struct( - &mut self, _name: &'static str, len: usize) - -> Result { + fn serialize_tuple_struct(&mut self, + _name: &'static str, + len: usize) + -> Result { self.serialize_tuple(len).map(TupleStructState) } - fn serialize_tuple_struct_elt( - &mut self, state: &mut TupleStructState, value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_struct_elt(&mut self, + state: &mut TupleStructState, + value: T) + -> Result<(), Error> + where T: Serialize, { self.serialize_tuple_elt(&mut state.0, value) } - fn serialize_tuple_struct_end( - &mut self, _state: TupleStructState) - -> Result<(), Error> { + fn serialize_tuple_struct_end(&mut self, + _state: TupleStructState) + -> Result<(), Error> { Ok(()) } - fn serialize_tuple_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_tuple_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_variant_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant_end( - &mut self, _state: ()) - -> Result<(), Error> { + fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_map( - &mut self, _len: Option) - -> Result<(), Error> { + fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_map_key( - &mut self, _state: &mut (), _key: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_key(&mut self, + _state: &mut (), + _key: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_pair()) } - fn serialize_map_value( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_value(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_pair()) } @@ -276,54 +275,51 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_struct(&mut self, _name: &'static str, _len: usize) + fn serialize_struct(&mut self, + _name: &'static str, + _len: usize) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_struct_elt( - &mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_struct_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_pair()) } - fn serialize_struct_end( - &mut self, _state: ()) - -> Result<(), Error> { + fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_struct_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_struct_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_struct_variant_elt( - &mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> { + fn serialize_struct_variant_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_struct_variant_end( - &mut self, _state: ()) - -> Result<(), Error> { + fn serialize_struct_variant_end(&mut self, + _state: ()) + -> Result<(), Error> { Err(Error::unsupported_pair()) } } -impl Error { +impl Error { fn unsupported_pair() -> Self { Error::Custom("unsupported pair".into()) } diff --git a/src/ser/value.rs b/src/ser/value.rs index d0172424..fcaf0f47 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -5,19 +5,18 @@ use std::str; use url::form_urlencoded; pub struct ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target + where Target: 'target + form_urlencoded::Target, { key: &'key mut Option>, - serializer: &'target mut form_urlencoded::Serializer + serializer: &'target mut form_urlencoded::Serializer, } impl<'key, 'target, Target> ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target + where Target: 'target + form_urlencoded::Target, { - pub fn new( - key: &'key mut Option>, - serializer: &'target mut form_urlencoded::Serializer) - -> Result { + pub fn new(key: &'key mut Option>, + serializer: &'target mut form_urlencoded::Serializer) + -> Result { if key.is_some() { Ok(ValueSerializer { key: key, @@ -40,7 +39,7 @@ impl<'key, 'target, Target> ValueSerializer<'key, 'target, Target> impl<'key, 'target, Target> Serializer for ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target + where Target: 'target + form_urlencoded::Target, { type Error = Error; type SeqState = (); @@ -122,37 +121,36 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_unit_struct( - &mut self, name: &'static str) - -> Result<(), Error> { + fn serialize_unit_struct(&mut self, + name: &'static str) + -> Result<(), Error> { self.append_pair(name) } - fn serialize_unit_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - variant: &'static str) - -> Result<(), Error> { + fn serialize_unit_variant(&mut self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result<(), Error> { self.append_pair(variant) } - fn serialize_newtype_struct( - &mut self, _name: &'static str, value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_struct(&mut self, + _name: &'static str, + value: T) + -> Result<(), Error> + where T: Serialize, { value.serialize(self) } - fn serialize_newtype_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_newtype_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -166,7 +164,7 @@ impl<'key, 'target, Target> Serializer } fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: Serialize + where T: Serialize, { value.serialize(self) } @@ -175,10 +173,11 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_seq_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_seq_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -195,10 +194,11 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_tuple_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -207,16 +207,18 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_tuple_struct( - &mut self, _name: &'static str, _len: usize) - -> Result<(), Error> { + fn serialize_tuple_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_value()) } - fn serialize_tuple_struct_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_struct_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -225,20 +227,20 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_tuple_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_tuple_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_value()) } - fn serialize_tuple_variant_elt( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_tuple_variant_elt(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -251,18 +253,20 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_map_key( - &mut self, _state: &mut (), _key: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_key(&mut self, + _state: &mut (), + _key: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } - fn serialize_map_value( - &mut self, _state: &mut (), _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_map_value(&mut self, + _state: &mut (), + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -271,19 +275,19 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_struct( - &mut self, _name: &'static str, _len: usize) - -> Result<(), Error> { + fn serialize_struct(&mut self, + _name: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_value()) } - fn serialize_struct_elt( - &mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize + fn serialize_struct_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> + where T: Serialize, { Err(Error::unsupported_value()) } @@ -292,32 +296,33 @@ impl<'key, 'target, Target> Serializer Err(Error::unsupported_value()) } - fn serialize_struct_variant( - &mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { + fn serialize_struct_variant(&mut self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result<(), Error> { Err(Error::unsupported_value()) } - fn serialize_struct_variant_elt( - &mut self, _state: &mut (), _key: &'static str, _value: T) - -> Result<(), Error> { + fn serialize_struct_variant_elt(&mut self, + _state: &mut (), + _key: &'static str, + _value: T) + -> Result<(), Error> { Err(Error::unsupported_value()) } - fn serialize_struct_variant_end( - &mut self, _state: ()) - -> Result<(), Error> { + fn serialize_struct_variant_end(&mut self, + _state: ()) + -> Result<(), Error> { Err(Error::unsupported_value()) } } impl Error { fn no_key() -> Self { - Error::Custom( - "tried to serialize a value before serializing key".into()) + Error::Custom("tried to serialize a value before serializing key" + .into()) } fn unsupported_value() -> Self { diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index b401ef94..e4e70eeb 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -2,50 +2,33 @@ extern crate serde_urlencoded; #[test] fn serialize_option_map_int() { - let params = &[ - ("first", Some(23)), - ("middle", None), - ("last", Some(42)), - ]; + let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; - assert_eq!( - serde_urlencoded::to_string(params), - Ok("first=23&last=42".to_owned())); + assert_eq!(serde_urlencoded::to_string(params), + Ok("first=23&last=42".to_owned())); } #[test] fn serialize_option_map_string() { - let params = &[ - ("first", Some("hello")), - ("middle", None), - ("last", Some("world")), - ]; + let params = + &[("first", Some("hello")), ("middle", None), ("last", Some("world"))]; - assert_eq!( - serde_urlencoded::to_string(params), - Ok("first=hello&last=world".to_owned())); + assert_eq!(serde_urlencoded::to_string(params), + Ok("first=hello&last=world".to_owned())); } #[test] fn serialize_option_map_bool() { - let params = &[ - ("one", Some(true)), - ("two", Some(false)) - ]; + let params = &[("one", Some(true)), ("two", Some(false))]; - assert_eq!( - serde_urlencoded::to_string(params), - Ok("one=true&two=false".to_owned())); + assert_eq!(serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned())); } #[test] fn serialize_map_bool() { - let params = &[ - ("one", true), - ("two", false) - ]; + let params = &[("one", true), ("two", false)]; - assert_eq!( - serde_urlencoded::to_string(params), - Ok("one=true&two=false".to_owned())); + assert_eq!(serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned())); } From 9960d5af2d853613ea8a7d26cf2d000358d09226 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Jan 2017 17:09:10 +0100 Subject: [PATCH 16/95] Update to serde 0.9.0 (fixes #7) --- Cargo.toml | 5 +- src/de.rs | 33 ++- src/ser/key.rs | 352 ++++++------------------------ src/ser/mod.rs | 551 ++++++++++++++++++++++++----------------------- src/ser/pair.rs | 452 ++++++++++++++++++++------------------ src/ser/part.rs | 311 ++++++++++++++++++++++++++ src/ser/value.rs | 338 +++-------------------------- 7 files changed, 957 insertions(+), 1085 deletions(-) create mode 100644 src/ser/part.rs diff --git a/Cargo.toml b/Cargo.toml index 95845cad..b9c18f07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,9 @@ documentation = "https://docs.rs/serde_urlencoded" description = "`x-www-form-urlencoded` meets Serde" keywords = ["serde", "serialization", "urlencoded"] +[lib] +test = false + [dependencies] -serde = "0.8.7" +serde = "0.9.2" url = "1.0.0" diff --git a/src/de.rs b/src/de.rs index 42c1f043..95208e9f 100644 --- a/src/de.rs +++ b/src/de.rs @@ -4,7 +4,6 @@ use serde::de; pub use serde::de::value::Error; use serde::de::value::MapDeserializer; -use std::borrow::Cow; use url::form_urlencoded::Parse as UrlEncodedParse; use url::form_urlencoded::parse; @@ -24,7 +23,7 @@ use url::form_urlencoded::parse; /// Ok(meal)); /// ``` pub fn from_bytes(input: &[u8]) -> Result { - T::deserialize(&mut Deserializer::new(parse(input))) + T::deserialize(Deserializer::new(parse(input))) } /// Deserializes a `application/x-wwww-url-encoded` value from a `&str`. @@ -56,61 +55,52 @@ pub fn from_str(input: &str) -> Result { /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'a> { - inner: MapDeserializer, - Cow<'a, str>, - Cow<'a, str>, - Error>, + inner: MapDeserializer, Error>, } impl<'a> Deserializer<'a> { /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'a>) -> Self { - Deserializer { inner: MapDeserializer::unbounded(parser) } + Deserializer { inner: MapDeserializer::new(parser) } } } impl<'a> de::Deserializer for Deserializer<'a> { type Error = Error; - fn deserialize(&mut self, visitor: V) -> Result + fn deserialize(self, visitor: V) -> Result where V: de::Visitor, { self.deserialize_map(visitor) } - fn deserialize_map(&mut self, - mut visitor: V) - -> Result + fn deserialize_map(self, visitor: V) -> Result where V: de::Visitor, { - visitor.visit_map(&mut self.inner) + visitor.visit_map(self.inner) } - fn deserialize_seq(&mut self, - mut visitor: V) - -> Result + fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor, { - visitor.visit_seq(&mut self.inner) + visitor.visit_seq(self.inner) } - fn deserialize_seq_fixed_size(&mut self, + fn deserialize_seq_fixed_size(self, _len: usize, - mut visitor: V) + visitor: V) -> Result where V: de::Visitor, { - visitor.visit_seq(&mut self.inner) + visitor.visit_seq(self.inner) } forward_to_deserialize! { bool - usize u8 u16 u32 u64 - isize i8 i16 i32 @@ -123,6 +113,7 @@ impl<'a> de::Deserializer for Deserializer<'a> { unit option bytes + byte_buf unit_struct newtype_struct tuple_struct diff --git a/src/ser/key.rs b/src/ser/key.rs index 0e5f7a67..149c8f65 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -1,302 +1,80 @@ - use ser::Error; -use serde::{Serialize, Serializer}; +use ser::part::Sink; +use serde::Serialize; use std::borrow::Cow; -use std::str; +use std::ops::Deref; -pub struct MapKeySerializer<'key>(&'key mut Option>); - -impl<'key> MapKeySerializer<'key> { - pub fn new(output: &'key mut Option>) -> Self { - MapKeySerializer(output) - } - - fn set_key(&mut self, key: T) -> Result<(), Error> - where T: Into>, - { - *self.0 = Some(key.into()); - Ok(()) - } +pub enum Key<'key> { + Static(&'static str), + Dynamic(Cow<'key, str>), } -impl<'key> Serializer for MapKeySerializer<'key> { - type Error = Error; - type SeqState = (); - type TupleState = (); - type TupleStructState = (); - type TupleVariantState = (); - type MapState = (); - type StructState = (); - type StructVariantState = (); +impl<'key> Deref for Key<'key> { + type Target = str; - fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_isize(&mut self, v: isize) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_i8(&mut self, v: i8) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_i16(&mut self, v: i16) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_i32(&mut self, v: i32) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_i64(&mut self, v: i64) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_usize(&mut self, v: usize) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_u8(&mut self, v: u8) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_u16(&mut self, v: u16) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_u32(&mut self, v: u32) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_u64(&mut self, v: u64) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_f32(&mut self, v: f32) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_f64(&mut self, v: f64) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_char(&mut self, v: char) -> Result<(), Error> { - self.set_key(v.to_string()) - } - - fn serialize_str(&mut self, value: &str) -> Result<(), Error> { - self.set_key(String::from(value)) - } - - fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Error> { - match str::from_utf8(value) { - Ok(value) => self.set_key(String::from(value)), - Err(err) => Err(Error::Utf8(err)), + fn deref(&self) -> &str { + match *self { + Key::Static(key) => key, + Key::Dynamic(ref key) => key, } } +} - fn serialize_unit(&mut self) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_unit_struct(&mut self, - name: &'static str) - -> Result<(), Error> { - self.set_key(name) - } - - fn serialize_unit_variant(&mut self, - _name: &'static str, - _variant_index: usize, - variant: &'static str) - -> Result<(), Error> { - self.set_key(variant) - } - - fn serialize_newtype_struct(&mut self, - _name: &'static str, - value: T) - -> Result<(), Error> - where T: Serialize, - { - value.serialize(self) - } - - fn serialize_newtype_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_none(&mut self) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_some(&mut self, _value: T) -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_seq_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple(&mut self, _len: usize) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_struct(&mut self, - _name: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_struct_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_variant_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_map_key(&mut self, - _state: &mut (), - _key: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_map_value(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_struct(&mut self, - _name: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_struct_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_key()) - } - - fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_struct_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_struct_variant_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> { - Err(Error::unsupported_key()) - } - - fn serialize_struct_variant_end(&mut self, - _state: ()) - -> Result<(), Error> { - Err(Error::unsupported_key()) +impl<'key> From> for Cow<'static, str> { + fn from(key: Key<'key>) -> Self { + match key { + Key::Static(key) => key.into(), + Key::Dynamic(key) => key.into_owned().into(), + } } } -impl Error { - fn unsupported_key() -> Self { +pub struct KeySink { + end: End, +} + +impl KeySink + where End: for<'key> FnOnce(Key<'key>) -> Result +{ + pub fn new(end: End) -> Self { + KeySink { end: end } + } +} + +impl Sink for KeySink + where End: for<'key> FnOnce(Key<'key>) -> Result +{ + type Ok = Ok; + + fn serialize_bool(self, _value: bool) -> Result { + Err(self.unsupported()) + } + + fn serialize_static_str(self, + value: &'static str) + -> Result { + (self.end)(Key::Static(value)) + } + + fn serialize_str(self, value: &str) -> Result { + (self.end)(Key::Dynamic(value.into())) + } + + fn serialize_string(self, value: String) -> Result { + (self.end)(Key::Dynamic(value.into())) + } + + fn serialize_none(self) -> Result { + Err(self.unsupported()) + } + + fn serialize_some(self, + _value: &T) + -> Result { + Err(self.unsupported()) + } + + fn unsupported(self) -> Error { Error::Custom("unsupported key".into()) } } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 00c0540a..400846f3 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -2,12 +2,14 @@ mod key; mod pair; +mod part; mod value; use serde::ser; use std::borrow::Cow; use std::error; use std::fmt; +use std::marker::PhantomData; use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; @@ -27,12 +29,9 @@ use url::form_urlencoded::Target as UrlEncodedTarget; /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); /// ``` pub fn to_string(input: &T) -> Result { - let mut output = String::new(); - { - let mut urlencoder = UrlEncodedSerializer::new(&mut output); - input.serialize(&mut Serializer::new(&mut urlencoder))?; - } - Ok(output) + let mut urlencoder = UrlEncodedSerializer::new("".to_owned()); + input.serialize(Serializer::new(&mut urlencoder))?; + Ok(urlencoder.finish()) } /// A serializer for the `application/x-www-form-urlencoded` format. @@ -44,13 +43,13 @@ pub fn to_string(input: &T) -> Result { /// unit structs and unit variants. /// /// * Newtype structs defer to their inner values. -pub struct Serializer<'output, T: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, +pub struct Serializer<'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer, } -impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { +impl<'output, Target: 'output + UrlEncodedTarget> Serializer<'output, Target> { /// Returns a new `Serializer`. - pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { + pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { Serializer { urlencoder: urlencoder } } } @@ -59,15 +58,13 @@ impl<'output, T: 'output + UrlEncodedTarget> Serializer<'output, T> { #[derive(Clone, Debug, PartialEq, Eq)] pub enum Error { Custom(Cow<'static, str>), - InvalidValue(Cow<'static, str>), Utf8(str::Utf8Error), } impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Custom(ref msg) => msg.fmt(f), - Error::InvalidValue(ref msg) => write!(f, "invalid value: {}", msg), Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), } } @@ -77,7 +74,6 @@ impl error::Error for Error { fn description(&self) -> &str { match *self { Error::Custom(ref msg) => msg, - Error::InvalidValue(ref msg) => msg, Error::Utf8(ref err) => error::Error::description(err), } } @@ -85,413 +81,432 @@ impl error::Error for Error { /// The lower-level cause of this error, in the case of a `Utf8` error. fn cause(&self) -> Option<&error::Error> { match *self { - Error::Custom(_) | - Error::InvalidValue(_) => None, + Error::Custom(_) => None, Error::Utf8(ref err) => Some(err), } } } impl ser::Error for Error { - fn custom>(msg: T) -> Self { - Error::Custom(msg.into().into()) - } - - fn invalid_value(msg: &str) -> Self { - Error::InvalidValue(String::from(msg).into()) + fn custom(msg: T) -> Self { + Error::Custom(format!("{}", msg).into()) } } -/// State used when serializing sequences. -pub struct SeqState { - _state: (), +/// Sequence serializer. +pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer, } -/// State used when serializing tuples. -pub struct TupleState { - _state: (), +/// Tuple serializer. +/// +/// Never instantiated, tuples are not supported at top-level. +pub struct TupleSerializer<'output, T: 'output + UrlEncodedTarget> { + _marker: PhantomData<&'output T>, } -/// State used when serializing tuple structs. -pub struct TupleStructState { - _state: (), +/// Tuple struct serializer. +/// +/// Never instantiated, tuple structs are not supported. +pub struct TupleStructSerializer<'output, T: 'output + UrlEncodedTarget> { + _marker: PhantomData<&'output T>, } -/// State used when serializing tuple variants. -pub struct TupleVariantState { - _state: (), +/// Tuple variant serializer. +/// +/// Never instantiated, tuple variants are not supported. +pub struct TupleVariantSerializer<'output, T: 'output + UrlEncodedTarget> { + _marker: PhantomData<&'output T>, } -/// State used when serializing maps. -pub struct MapState { +/// Map serializer. +pub struct MapSerializer<'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer, key: Option>, } -/// State used when serializing structs. -pub struct StructState { - _state: (), +/// Struct serializer. +pub struct StructSerializer<'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer, } -/// State used when serializing struct variants. -pub struct StructVariantState { - _state: (), +/// Struct variant serializer. +/// +/// Never instantiated, struct variants are not supported. +pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { + _marker: PhantomData<&'output T>, } impl<'output, Target> ser::Serializer for Serializer<'output, Target> where Target: 'output + UrlEncodedTarget, { + type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - - /// State used when serializing sequences. - type SeqState = SeqState; - - /// State used when serializing tuples. - type TupleState = TupleState; - - /// State used when serializing tuple structs. - type TupleStructState = TupleStructState; - - /// State used when serializing tuple variants. - type TupleVariantState = TupleVariantState; - - /// State used when serializing maps. - type MapState = MapState; - - /// State used when serializing structs. - type StructState = StructState; - - /// State used when serializing struct variants. - type StructVariantState = StructVariantState; + type SerializeSeq = SeqSerializer<'output, Target>; + type SerializeTuple = TupleSerializer<'output, Target>; + type SerializeTupleStruct = TupleStructSerializer<'output, Target>; + type SerializeTupleVariant = TupleVariantSerializer<'output, Target>; + type SerializeMap = MapSerializer<'output, Target>; + type SerializeStruct = StructSerializer<'output, Target>; + type SerializeStructVariant = StructVariantSerializer<'output, Target>; /// Returns an error. - fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { + fn serialize_bool(self, _v: bool) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_isize(&mut self, _v: isize) -> Result<(), Error> { + fn serialize_i8(self, _v: i8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i8(&mut self, _v: i8) -> Result<(), Error> { + fn serialize_i16(self, _v: i16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i16(&mut self, _v: i16) -> Result<(), Error> { + fn serialize_i32(self, _v: i32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i32(&mut self, _v: i32) -> Result<(), Error> { + fn serialize_i64(self, _v: i64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i64(&mut self, _v: i64) -> Result<(), Error> { + fn serialize_u8(self, _v: u8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_usize(&mut self, _v: usize) -> Result<(), Error> { + fn serialize_u16(self, _v: u16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u8(&mut self, _v: u8) -> Result<(), Error> { + fn serialize_u32(self, _v: u32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u16(&mut self, _v: u16) -> Result<(), Error> { + fn serialize_u64(self, _v: u64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u32(&mut self, _v: u32) -> Result<(), Error> { + fn serialize_f32(self, _v: f32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u64(&mut self, _v: u64) -> Result<(), Error> { + fn serialize_f64(self, _v: f64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f32(&mut self, _v: f32) -> Result<(), Error> { + fn serialize_char(self, _v: char) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f64(&mut self, _v: f64) -> Result<(), Error> { + fn serialize_str(self, _value: &str) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_char(&mut self, _v: char) -> Result<(), Error> { + fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_str(&mut self, _value: &str) -> Result<(), Error> { + fn serialize_unit(self) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_bytes(&mut self, _value: &[u8]) -> Result<(), Error> { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_unit(&mut self) -> Result<(), Error> { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_unit_struct(&mut self, + fn serialize_unit_struct(self, _name: &'static str) - -> Result<(), Error> { + -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_unit_variant(&mut self, + fn serialize_unit_variant(self, _name: &'static str, _variant_index: usize, _variant: &'static str) - -> Result<(), Error> { + -> Result { Err(Error::top_level()) } /// Serializes the inner value, ignoring the newtype name. - fn serialize_newtype_struct(&mut self, - _name: &'static str, - value: T) - -> Result<(), Error> - where T: ser::Serialize, - { + fn serialize_newtype_struct + (self, + _name: &'static str, + value: &T) + -> Result { value.serialize(self) } /// Returns an error. - fn serialize_newtype_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: ser::Serialize, - { + fn serialize_newtype_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: &T) + -> Result { Err(Error::top_level()) } - /// Returns an error. - fn serialize_none(&mut self) -> Result<(), Error> { - Ok(()) + /// Returns `Ok`. + fn serialize_none(self) -> Result { + Ok(self.urlencoder) } - /// Returns an error. - fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: ser::Serialize, - { + /// Serializes the given value. + fn serialize_some + (self, + value: &T) + -> Result { value.serialize(self) } - /// Begins to serialize a sequence, given length (if any) is ignored. - fn serialize_seq(&mut self, + /// Serialize a sequence, given length (if any) is ignored. + fn serialize_seq(self, _len: Option) - -> Result { - Ok(SeqState { _state: () }) + -> Result { + Ok(SeqSerializer { urlencoder: self.urlencoder }) } - /// Serializes a sequence element. - fn serialize_seq_elt(&mut self, - _state: &mut SeqState, - value: T) - -> Result<(), Error> - where T: ser::Serialize, - { - value.serialize(&mut pair::PairSerializer::new(self.urlencoder)) - } - - /// Finishes serializing a sequence. - fn serialize_seq_end(&mut self, _state: SeqState) -> Result<(), Error> { - Ok(()) - } - - /// Begins to serialize a sequence, given length is ignored. - fn serialize_seq_fixed_size(&mut self, - _length: usize) - -> Result { - Ok(SeqState { _state: () }) + /// Serializes a sequence, given length is ignored. + fn serialize_seq_fixed_size(self, + _len: usize) + -> Result { + Ok(SeqSerializer { urlencoder: self.urlencoder }) } /// Returns an error. - fn serialize_tuple(&mut self, _len: usize) -> Result { + fn serialize_tuple(self, + _len: usize) + -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_elt(&mut self, - _state: &mut TupleState, - _value: T) - -> Result<(), Error> - where T: ser::Serialize, - { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_end(&mut self, _state: TupleState) -> Result<(), Error> { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_struct(&mut self, + fn serialize_tuple_struct(self, _name: &'static str, _len: usize) - -> Result { + -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_struct_elt(&mut self, - _state: &mut TupleStructState, - _value: T) - -> Result<(), Error> - where T: ser::Serialize, - { + fn serialize_tuple_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(Error::top_level()) } - /// Returns an error. - fn serialize_tuple_struct_end(&mut self, - _state: TupleStructState) - -> Result<(), Error> { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_variant_elt(&mut self, - _state: &mut TupleVariantState, - _value: T) - -> Result<(), Error> - where T: ser::Serialize, - { - Err(Error::top_level()) - } - - /// Returns an error. - fn serialize_tuple_variant_end(&mut self, - _state: TupleVariantState) - -> Result<(), Error> { - Err(Error::top_level()) - } - - /// Begins to serialize a map, given length (if any) is ignored. - fn serialize_map(&mut self, + /// Serializes a map, given length is ignored. + fn serialize_map(self, _len: Option) - -> Result { - Ok(MapState { key: None }) + -> Result { + Ok(MapSerializer { + urlencoder: self.urlencoder, + key: None, + }) } - /// Serializes a map key. - fn serialize_map_key(&mut self, - state: &mut MapState, - key: T) - -> Result<(), Error> - where T: ser::Serialize, - { - key.serialize(&mut key::MapKeySerializer::new(&mut state.key)) - } - - /// Serializes a map value. - fn serialize_map_value(&mut self, - state: &mut MapState, - value: T) - -> Result<(), Error> - where T: ser::Serialize, - { - let mut value_serializer = - value::ValueSerializer::new(&mut state.key, self.urlencoder)?; - value.serialize(&mut value_serializer) - } - - /// Finishes serializing a map. - fn serialize_map_end(&mut self, _state: MapState) -> Result<(), Error> { - Ok(()) - } - - /// Begins to serialize a struct, given length is ignored. - fn serialize_struct(&mut self, + /// Serializes a struct, given length is ignored. + fn serialize_struct(self, _name: &'static str, _len: usize) - -> Result { - Ok(StructState { _state: () }) + -> Result { + Ok(StructSerializer { urlencoder: self.urlencoder }) } - /// Serializes a struct element. - fn serialize_struct_elt(&mut self, - _state: &mut StructState, - key: &'static str, - value: T) - -> Result<(), Error> - where T: ser::Serialize, - { - let mut key = Some(key.into()); - let mut value_serializer = - value::ValueSerializer::new(&mut key, self.urlencoder).unwrap(); - value.serialize(&mut value_serializer) + /// Returns an error. + fn serialize_struct_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(Error::top_level()) + } +} + +impl<'output, Target> ser::SerializeSeq for SeqSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_element(&mut self, + value: &T) + -> Result<(), Error> { + value.serialize(pair::PairSerializer::new(self.urlencoder)) } - /// Finishes serializing a struct. - fn serialize_struct_end(&mut self, - _state: StructState) - -> Result<(), Error> { + fn end(self) -> Result { + Ok(self.urlencoder) + } +} + +impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl<'output, Target> ser::SerializeTupleStruct + for TupleStructSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl<'output, Target> ser::SerializeTupleVariant + for TupleVariantSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_entry + (&mut self, + key: &K, + value: &V) + -> Result<(), Error> { + let key_sink = key::KeySink::new(|key| { + let value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(value_sink))?; + self.key = None; + Ok(()) + }); + let entry_serializer = part::PartSerializer::new(key_sink); + key.serialize(entry_serializer) + } + + fn serialize_key(&mut self, + key: &T) + -> Result<(), Error> { + let key_sink = key::KeySink::new(|key| Ok(key.into())); + let key_serializer = part::PartSerializer::new(key_sink); + self.key = Some(key.serialize(key_serializer)?); Ok(()) } - /// Returns an error. - fn serialize_struct_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { - Err(Error::top_level()) + fn serialize_value(&mut self, + value: &T) + -> Result<(), Error> { + { + let key = self.key.as_ref().ok_or_else(|| Error::no_key())?; + let value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(value_sink))?; + } + self.key = None; + Ok(()) } - /// Returns an error. - fn serialize_struct_variant_elt(&mut self, - _state: &mut StructVariantState, - _key: &'static str, - _value: T) - -> Result<(), Error> { - Err(Error::top_level()) + fn end(self) -> Result { + Ok(self.urlencoder) + } +} + +impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_field(&mut self, + key: &'static str, + value: &T) + -> Result<(), Error> { + let value_sink = value::ValueSink::new(self.urlencoder, key); + value.serialize(part::PartSerializer::new(value_sink)) } - /// Returns an error. - fn serialize_struct_variant_end(&mut self, - _state: StructVariantState) - -> Result<(), Error> { - Err(Error::top_level()) + fn end(self) -> Result { + Ok(self.urlencoder) + } +} + +impl<'output, Target> ser::SerializeStructVariant + for StructVariantSerializer<'output, Target> + where Target: 'output + UrlEncodedTarget, +{ + type Ok = &'output mut UrlEncodedSerializer; + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() } } impl Error { fn top_level() -> Self { - Error::Custom("top-level serializer supports only maps and structs" - .into()) + let msg = "top-level serializer supports only maps and structs"; + Error::Custom(msg.into()) + } + + fn no_key() -> Self { + let msg = "tried to serialize a value before serializing key"; + Error::Custom(msg.into()) } } diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 36eda51a..3d916371 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -1,111 +1,107 @@ -use ser::{Error, key, value}; -use serde::{Serialize, Serializer}; +use ser::Error; +use ser::key::KeySink; +use ser::part::PartSerializer; +use ser::value::ValueSink; +use serde::ser; use std::borrow::Cow; -use url::form_urlencoded; +use std::mem; +use url::form_urlencoded::Serializer as UrlEncodedSerializer; +use url::form_urlencoded::Target as UrlEncodedTarget; -pub struct PairSerializer<'target, Target>( - &'target mut form_urlencoded::Serializer) - where Target: 'target + form_urlencoded::Target; +pub struct PairSerializer<'target, Target: 'target + UrlEncodedTarget> { + urlencoder: &'target mut UrlEncodedSerializer, + state: PairState, +} impl<'target, Target> PairSerializer<'target, Target> - where Target: 'target + form_urlencoded::Target, + where Target: 'target + UrlEncodedTarget, { - pub fn new(serializer: &'target mut form_urlencoded::Serializer) - -> Self { - PairSerializer(serializer) + pub fn new(urlencoder: &'target mut UrlEncodedSerializer) -> Self { + PairSerializer { + urlencoder: urlencoder, + state: PairState::WaitingForKey, + } } } -pub struct TupleState(Option>>); -pub struct TupleStructState(TupleState); - -impl<'target, Target> Serializer for PairSerializer<'target, Target> - where Target: 'target + form_urlencoded::Target, +impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, { + type Ok = (); type Error = Error; - type SeqState = (); - type TupleState = TupleState; - type TupleStructState = TupleStructState; - type TupleVariantState = (); - type MapState = (); - type StructState = (); - type StructVariantState = (); + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; - fn serialize_bool(&mut self, _v: bool) -> Result<(), Error> { - Err(Error::Custom("booleans are not supported values".into())) - } - - fn serialize_isize(&mut self, _v: isize) -> Result<(), Error> { + fn serialize_bool(self, _v: bool) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_i8(&mut self, _v: i8) -> Result<(), Error> { + fn serialize_i8(self, _v: i8) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_i16(&mut self, _v: i16) -> Result<(), Error> { + fn serialize_i16(self, _v: i16) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_i32(&mut self, _v: i32) -> Result<(), Error> { + fn serialize_i32(self, _v: i32) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_i64(&mut self, _v: i64) -> Result<(), Error> { + fn serialize_i64(self, _v: i64) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_usize(&mut self, _v: usize) -> Result<(), Error> { + fn serialize_u8(self, _v: u8) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_u8(&mut self, _v: u8) -> Result<(), Error> { + fn serialize_u16(self, _v: u16) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_u16(&mut self, _v: u16) -> Result<(), Error> { + fn serialize_u32(self, _v: u32) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_u32(&mut self, _v: u32) -> Result<(), Error> { + fn serialize_u64(self, _v: u64) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_u64(&mut self, _v: u64) -> Result<(), Error> { + fn serialize_f32(self, _v: f32) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_f32(&mut self, _v: f32) -> Result<(), Error> { + fn serialize_f64(self, _v: f64) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_f64(&mut self, _v: f64) -> Result<(), Error> { + fn serialize_char(self, _v: char) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_char(&mut self, _v: char) -> Result<(), Error> { + fn serialize_str(self, _value: &str) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_str(&mut self, _value: &str) -> Result<(), Error> { + fn serialize_bytes(self, _value: &[u8]) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_bytes(&mut self, _value: &[u8]) -> Result<(), Error> { + fn serialize_unit(self) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_unit(&mut self) -> Result<(), Error> { + fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_unit_struct(&mut self, - _name: &'static str) - -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_unit_variant(&mut self, + fn serialize_unit_variant(self, _name: &'static str, _variant_index: usize, _variant: &'static str) @@ -113,213 +109,259 @@ impl<'target, Target> Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_newtype_struct(&mut self, - _name: &'static str, - value: T) - -> Result<(), Error> - where T: Serialize, - { + fn serialize_newtype_struct + (self, + _name: &'static str, + value: &T) + -> Result<(), Error> { value.serialize(self) } - fn serialize_newtype_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { + fn serialize_newtype_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: &T) + -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_none(&mut self) -> Result<(), Error> { + fn serialize_none(self) -> Result<(), Error> { Ok(()) } - fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: Serialize, - { + fn serialize_some(self, + value: &T) + -> Result<(), Error> { value.serialize(self) } - fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { + fn serialize_seq(self, _len: Option) -> Result { Err(Error::unsupported_pair()) } - fn serialize_seq_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { + fn serialize_seq_fixed_size(self, _len: usize) -> Result { Err(Error::unsupported_pair()) } - fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_tuple(&mut self, len: usize) -> Result { + fn serialize_tuple(self, len: usize) -> Result { if len == 2 { - Ok(TupleState(None)) + Ok(self) } else { Err(Error::unsupported_pair()) } } - fn serialize_tuple_elt(&mut self, - state: &mut TupleState, - value: T) - -> Result<(), Error> - where T: Serialize, - { - match state.0.take() { - None => { - let mut key = None; - { - let mut key_serializer = - key::MapKeySerializer::new(&mut key); - value.serialize(&mut key_serializer)?; - } - state.0 = Some(key); - Ok(()) - }, - Some(ref mut key) => { - { - let mut value_serializer = - value::ValueSerializer::new(key, &mut self.0).unwrap(); - value.serialize(&mut value_serializer)?; - } - state.0 = Some(None); - Ok(()) - }, - } - } - - fn serialize_tuple_end(&mut self, _state: TupleState) -> Result<(), Error> { - Ok(()) - } - - fn serialize_tuple_struct(&mut self, + fn serialize_tuple_struct(self, _name: &'static str, - len: usize) - -> Result { - self.serialize_tuple(len).map(TupleStructState) + _len: usize) + -> Result { + Err(Error::unsupported_pair()) } - fn serialize_tuple_struct_elt(&mut self, - state: &mut TupleStructState, - value: T) - -> Result<(), Error> - where T: Serialize, - { - self.serialize_tuple_elt(&mut state.0, value) - } - - fn serialize_tuple_struct_end(&mut self, - _state: TupleStructState) - -> Result<(), Error> { - Ok(()) - } - - fn serialize_tuple_variant(&mut self, + fn serialize_tuple_variant(self, _name: &'static str, _variant_index: usize, _variant: &'static str, _len: usize) - -> Result<(), Error> { + -> Result { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { + fn serialize_map(self, _len: Option) -> Result { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_map_key(&mut self, - _state: &mut (), - _key: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_pair()) - } - - fn serialize_map_value(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_pair()) - } - - fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_struct(&mut self, + fn serialize_struct(self, _name: &'static str, _len: usize) - -> Result<(), Error> { + -> Result { Err(Error::unsupported_pair()) } - fn serialize_struct_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_pair()) - } - - fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_struct_variant(&mut self, + fn serialize_struct_variant(self, _name: &'static str, _variant_index: usize, _variant: &'static str, _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - fn serialize_struct_variant_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_struct_variant_end(&mut self, - _state: ()) - -> Result<(), Error> { + -> Result { Err(Error::unsupported_pair()) } } +impl<'target, Target> ser::SerializeSeq for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +impl<'target, Target> ser::SerializeTuple for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, + value: &T) + -> Result<(), Error> { + match mem::replace(&mut self.state, PairState::Done) { + PairState::WaitingForKey => { + let key_sink = KeySink::new(|key| Ok(key.into())); + let key_serializer = PartSerializer::new(key_sink); + self.state = PairState::WaitingForValue { + key: value.serialize(key_serializer)?, + }; + Ok(()) + }, + PairState::WaitingForValue { key } => { + let result = { + let value_sink = ValueSink::new(self.urlencoder, &key); + let value_serializer = PartSerializer::new(value_sink); + value.serialize(value_serializer) + }; + if result.is_ok() { + self.state = PairState::Done; + } else { + self.state = PairState::WaitingForValue { key: key }; + } + result + }, + PairState::Done => Err(Error::done()), + } + } + + fn end(self) -> Result<(), Error> { + if let PairState::Done = self.state { + Ok(()) + } else { + Err(Error::not_done()) + } + } +} + +impl<'target, Target> ser::SerializeTupleStruct + for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +impl<'target, Target> ser::SerializeTupleVariant + for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +impl<'target, Target> ser::SerializeMap for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, + _key: &T) + -> Result<(), Error> { + unreachable!() + } + + fn serialize_value(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +impl<'target, Target> ser::SerializeStruct for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +impl<'target, Target> ser::SerializeStructVariant + for PairSerializer<'target, Target> + where Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result<(), Error> { + unreachable!() + } +} + +enum PairState { + WaitingForKey, + WaitingForValue { key: Cow<'static, str> }, + Done, +} + impl Error { + fn done() -> Self { + Error::Custom("this pair has already been serialized".into()) + } + + fn not_done() -> Self { + Error::Custom("this pair has not yet been serialized".into()) + } + fn unsupported_pair() -> Self { Error::Custom("unsupported pair".into()) } diff --git a/src/ser/part.rs b/src/ser/part.rs new file mode 100644 index 00000000..a8654508 --- /dev/null +++ b/src/ser/part.rs @@ -0,0 +1,311 @@ +use ser::Error; +use serde::ser; +use std::str; + +pub struct PartSerializer { + sink: S, +} + +impl PartSerializer { + pub fn new(sink: S) -> Self { + PartSerializer { sink: sink } + } +} + +pub trait Sink: Sized { + type Ok; + + fn serialize_bool(self, value: bool) -> Result; + + fn serialize_static_str(self, + value: &'static str) + -> Result; + + fn serialize_str(self, value: &str) -> Result; + fn serialize_string(self, value: String) -> Result; + fn serialize_none(self) -> Result; + + fn serialize_some + (self, + value: &T) + -> Result; + + fn unsupported(self) -> Error; +} + +impl ser::Serializer for PartSerializer { + type Ok = S::Ok; + type Error = Error; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> Result { + self.sink.serialize_bool(v) + } + + fn serialize_i8(self, v: i8) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_i16(self, v: i16) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_i32(self, v: i32) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_i64(self, v: i64) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_u8(self, v: u8) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_u16(self, v: u16) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_u32(self, v: u32) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_u64(self, v: u64) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_f32(self, v: f32) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_f64(self, v: f64) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_char(self, v: char) -> Result { + self.sink.serialize_string(v.to_string()) + } + + fn serialize_str(self, value: &str) -> Result { + self.sink.serialize_str(value) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + match str::from_utf8(value) { + Ok(value) => self.sink.serialize_str(value), + Err(err) => Err(Error::Utf8(err)), + } + } + + fn serialize_unit(self) -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result { + self.sink.serialize_static_str(name.into()) + } + + fn serialize_unit_variant(self, + _name: &'static str, + _variant_index: usize, + variant: &'static str) + -> Result { + self.sink.serialize_static_str(variant.into()) + } + + fn serialize_newtype_struct + (self, + _name: &'static str, + value: &T) + -> Result { + value.serialize(self) + } + + fn serialize_newtype_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _value: &T) + -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_none(self) -> Result { + self.sink.serialize_none() + } + + fn serialize_some(self, + value: &T) + -> Result { + self.sink.serialize_some(value) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(self.sink.unsupported()) + } + + + fn serialize_seq_fixed_size(self, _len: usize) -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_tuple_struct(self, + _name: &'static str, + _len: usize) + -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_tuple_variant(self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_map(self, _len: Option) -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_struct(self, + _name: &'static str, + _len: usize) + -> Result { + Err(self.sink.unsupported()) + } + + fn serialize_struct_variant(self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { + Err(self.sink.unsupported()) + } +} + +impl ser::SerializeSeq for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeTuple for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeTupleStruct for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeTupleVariant for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeMap for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_key(&mut self, + _key: &T) + -> Result<(), Error> { + unreachable!() + } + + fn serialize_value(&mut self, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeStruct for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} + +impl ser::SerializeStructVariant for PartSerializer { + type Ok = S::Ok; + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + unreachable!() + } + + fn end(self) -> Result { + unreachable!() + } +} diff --git a/src/ser/value.rs b/src/ser/value.rs index fcaf0f47..4bba0028 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -1,331 +1,63 @@ use ser::Error; -use serde::{Serialize, Serializer}; -use std::borrow::Cow; +use ser::part::{PartSerializer, Sink}; +use serde::ser::Serialize; use std::str; -use url::form_urlencoded; +use url::form_urlencoded::Serializer as UrlEncodedSerializer; +use url::form_urlencoded::Target as UrlEncodedTarget; -pub struct ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target, +pub struct ValueSink<'key, 'target, Target> + where Target: 'target + UrlEncodedTarget, { - key: &'key mut Option>, - serializer: &'target mut form_urlencoded::Serializer, + urlencoder: &'target mut UrlEncodedSerializer, + key: &'key str, } -impl<'key, 'target, Target> ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target, +impl<'key, 'target, Target> ValueSink<'key, 'target, Target> + where Target: 'target + UrlEncodedTarget, { - pub fn new(key: &'key mut Option>, - serializer: &'target mut form_urlencoded::Serializer) - -> Result { - if key.is_some() { - Ok(ValueSerializer { - key: key, - serializer: serializer, - }) - } else { - Err(Error::no_key()) - } - } - - fn append_pair(&mut self, value: &str) -> Result<(), Error> { - if let Some(key) = self.key.take() { - self.serializer.append_pair(&key, value); - Ok(()) - } else { - Err(Error::no_key()) + pub fn new(urlencoder: &'target mut UrlEncodedSerializer, + key: &'key str) + -> Self { + ValueSink { + urlencoder: urlencoder, + key: key, } } } -impl<'key, 'target, Target> Serializer - for ValueSerializer<'key, 'target, Target> - where Target: 'target + form_urlencoded::Target, +impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> + where Target: 'target + UrlEncodedTarget, { - type Error = Error; - type SeqState = (); - type TupleState = (); - type TupleStructState = (); - type TupleVariantState = (); - type MapState = (); - type StructState = (); - type StructVariantState = (); + type Ok = (); - fn serialize_bool(&mut self, v: bool) -> Result<(), Error> { - self.append_pair(if v { "true" } else { "false" }) + fn serialize_bool(self, value: bool) -> Result { + self.serialize_string(value.to_string()) } - fn serialize_isize(&mut self, v: isize) -> Result<(), Error> { - self.append_pair(&v.to_string()) + fn serialize_str(self, value: &str) -> Result<(), Error> { + self.urlencoder.append_pair(self.key, value); + Ok(()) } - fn serialize_i8(&mut self, v: i8) -> Result<(), Error> { - self.append_pair(&v.to_string()) + fn serialize_static_str(self, value: &'static str) -> Result<(), Error> { + self.serialize_str(value) } - fn serialize_i16(&mut self, v: i16) -> Result<(), Error> { - self.append_pair(&v.to_string()) + fn serialize_string(self, value: String) -> Result<(), Error> { + self.serialize_str(&value) } - fn serialize_i32(&mut self, v: i32) -> Result<(), Error> { - self.append_pair(&v.to_string()) + fn serialize_none(self) -> Result { + Ok(()) } - fn serialize_i64(&mut self, v: i64) -> Result<(), Error> { - self.append_pair(&v.to_string()) + fn serialize_some(self, + value: &T) + -> Result { + value.serialize(PartSerializer::new(self)) } - fn serialize_usize(&mut self, v: usize) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_u8(&mut self, v: u8) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_u16(&mut self, v: u16) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_u32(&mut self, v: u32) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_u64(&mut self, v: u64) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_f32(&mut self, v: f32) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_f64(&mut self, v: f64) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_char(&mut self, v: char) -> Result<(), Error> { - self.append_pair(&v.to_string()) - } - - fn serialize_str(&mut self, value: &str) -> Result<(), Error> { - self.append_pair(value) - } - - fn serialize_bytes(&mut self, value: &[u8]) -> Result<(), Error> { - match str::from_utf8(value) { - Ok(value) => self.append_pair(value), - Err(err) => Err(Error::Utf8(err)), - } - } - - fn serialize_unit(&mut self) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_unit_struct(&mut self, - name: &'static str) - -> Result<(), Error> { - self.append_pair(name) - } - - fn serialize_unit_variant(&mut self, - _name: &'static str, - _variant_index: usize, - variant: &'static str) - -> Result<(), Error> { - self.append_pair(variant) - } - - fn serialize_newtype_struct(&mut self, - _name: &'static str, - value: T) - -> Result<(), Error> - where T: Serialize, - { - value.serialize(self) - } - - fn serialize_newtype_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_none(&mut self) -> Result<(), Error> { - if let Some(_) = self.key.take() { - Ok(()) - } else { - Err(Error::no_key()) - } - } - - fn serialize_some(&mut self, value: T) -> Result<(), Error> - where T: Serialize, - { - value.serialize(self) - } - - fn serialize_seq(&mut self, _len: Option) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_seq_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_seq_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_seq_fixed_size(&mut self, _size: usize) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple(&mut self, _len: usize) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_struct(&mut self, - _name: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_struct_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_struct_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_variant_elt(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_tuple_variant_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_map(&mut self, _len: Option) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_map_key(&mut self, - _state: &mut (), - _key: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_map_value(&mut self, - _state: &mut (), - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_map_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_struct(&mut self, - _name: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_struct_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> - where T: Serialize, - { - Err(Error::unsupported_value()) - } - - fn serialize_struct_end(&mut self, _state: ()) -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_struct_variant(&mut self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } - fn serialize_struct_variant_elt(&mut self, - _state: &mut (), - _key: &'static str, - _value: T) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } - - fn serialize_struct_variant_end(&mut self, - _state: ()) - -> Result<(), Error> { - Err(Error::unsupported_value()) - } -} - -impl Error { - fn no_key() -> Self { - Error::Custom("tried to serialize a value before serializing key" - .into()) - } - - fn unsupported_value() -> Self { + fn unsupported(self) -> Error { Error::Custom("unsupported value".into()) } } From fa8fb69da0b3a9d24bff09da3795e54d6b20a157 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Jan 2017 23:01:20 +0100 Subject: [PATCH 17/95] Do not allocate a String to serialize a bool --- src/ser/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ser/value.rs b/src/ser/value.rs index 4bba0028..34ea7d02 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -31,7 +31,7 @@ impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> type Ok = (); fn serialize_bool(self, value: bool) -> Result { - self.serialize_string(value.to_string()) + self.serialize_static_str(if value { "true" } else { "false" }) } fn serialize_str(self, value: &str) -> Result<(), Error> { From e140c2b5c5bb5abab7fcc6a9d4540aaa3bf566a6 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Jan 2017 23:52:52 +0100 Subject: [PATCH 18/95] Use void for the unreachable serializers --- Cargo.toml | 1 + src/lib.rs | 1 + src/ser/mod.rs | 36 +++++----- src/ser/pair.rs | 146 ++++++---------------------------------- src/ser/part.rs | 174 ++++++++++-------------------------------------- src/ser/void.rs | 122 +++++++++++++++++++++++++++++++++ 6 files changed, 198 insertions(+), 282 deletions(-) create mode 100644 src/ser/void.rs diff --git a/Cargo.toml b/Cargo.toml index b9c18f07..a68819a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ test = false [dependencies] serde = "0.9.2" url = "1.0.0" +void = "1.0.2" diff --git a/src/lib.rs b/src/lib.rs index bacb67f7..0c1a99e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate serde; extern crate url; +extern crate void; pub mod de; pub mod ser; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 400846f3..50355fda 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -4,12 +4,12 @@ mod key; mod pair; mod part; mod value; +mod void; use serde::ser; use std::borrow::Cow; use std::error; use std::fmt; -use std::marker::PhantomData; use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; @@ -102,21 +102,21 @@ pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { /// /// Never instantiated, tuples are not supported at top-level. pub struct TupleSerializer<'output, T: 'output + UrlEncodedTarget> { - _marker: PhantomData<&'output T>, + inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. pub struct TupleStructSerializer<'output, T: 'output + UrlEncodedTarget> { - _marker: PhantomData<&'output T>, + inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. pub struct TupleVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - _marker: PhantomData<&'output T>, + inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, } /// Map serializer. @@ -134,7 +134,7 @@ pub struct StructSerializer<'output, Target: 'output + UrlEncodedTarget> { /// /// Never instantiated, struct variants are not supported. pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - _marker: PhantomData<&'output T>, + inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, } impl<'output, Target> ser::Serializer for Serializer<'output, Target> @@ -368,13 +368,13 @@ impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> type Error = Error; fn serialize_element(&mut self, - _value: &T) + value: &T) -> Result<(), Error> { - unreachable!() + self.inner.serialize_element(value) } fn end(self) -> Result { - unreachable!() + self.inner.end() } } @@ -386,13 +386,13 @@ impl<'output, Target> ser::SerializeTupleStruct type Error = Error; fn serialize_field(&mut self, - _value: &T) + value: &T) -> Result<(), Error> { - unreachable!() + self.inner.serialize_field(value) } fn end(self) -> Result { - unreachable!() + self.inner.end() } } @@ -404,13 +404,13 @@ impl<'output, Target> ser::SerializeTupleVariant type Error = Error; fn serialize_field(&mut self, - _value: &T) + value: &T) -> Result<(), Error> { - unreachable!() + self.inner.serialize_field(value) } fn end(self) -> Result { - unreachable!() + self.inner.end() } } @@ -488,14 +488,14 @@ impl<'output, Target> ser::SerializeStructVariant type Error = Error; fn serialize_field(&mut self, - _key: &'static str, - _value: &T) + key: &'static str, + value: &T) -> Result<(), Error> { - unreachable!() + self.inner.serialize_field(key, value) } fn end(self) -> Result { - unreachable!() + self.inner.end() } } diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 3d916371..743b3ddc 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -2,6 +2,7 @@ use ser::Error; use ser::key::KeySink; use ser::part::PartSerializer; use ser::value::ValueSink; +use ser::void::VoidSerializer; use serde::ser; use std::borrow::Cow; use std::mem; @@ -29,13 +30,13 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> { type Ok = (); type Error = Error; - type SerializeSeq = Self; + type SerializeSeq = VoidSerializer<()>; type SerializeTuple = Self; - type SerializeTupleStruct = Self; - type SerializeTupleVariant = Self; - type SerializeMap = Self; - type SerializeStruct = Self; - type SerializeStructVariant = Self; + type SerializeTupleStruct = VoidSerializer<()>; + type SerializeTupleVariant = VoidSerializer<()>; + type SerializeMap = VoidSerializer<()>; + type SerializeStruct = VoidSerializer<()>; + type SerializeStructVariant = VoidSerializer<()>; fn serialize_bool(self, _v: bool) -> Result<(), Error> { Err(Error::unsupported_pair()) @@ -137,11 +138,15 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> value.serialize(self) } - fn serialize_seq(self, _len: Option) -> Result { + fn serialize_seq(self, + _len: Option) + -> Result, Error> { Err(Error::unsupported_pair()) } - fn serialize_seq_fixed_size(self, _len: usize) -> Result { + fn serialize_seq_fixed_size(self, + _len: usize) + -> Result, Error> { Err(Error::unsupported_pair()) } @@ -156,7 +161,7 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_tuple_struct(self, _name: &'static str, _len: usize) - -> Result { + -> Result, Error> { Err(Error::unsupported_pair()) } @@ -165,18 +170,20 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> _variant_index: usize, _variant: &'static str, _len: usize) - -> Result { + -> Result, Error> { Err(Error::unsupported_pair()) } - fn serialize_map(self, _len: Option) -> Result { + fn serialize_map(self, + _len: Option) + -> Result, Error> { Err(Error::unsupported_pair()) } fn serialize_struct(self, _name: &'static str, _len: usize) - -> Result { + -> Result, Error> { Err(Error::unsupported_pair()) } @@ -185,28 +192,11 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> _variant_index: usize, _variant: &'static str, _len: usize) - -> Result { + -> Result, Error> { Err(Error::unsupported_pair()) } } -impl<'target, Target> ser::SerializeSeq for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_element(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - impl<'target, Target> ser::SerializeTuple for PairSerializer<'target, Target> where Target: 'target + UrlEncodedTarget, { @@ -251,102 +241,6 @@ impl<'target, Target> ser::SerializeTuple for PairSerializer<'target, Target> } } -impl<'target, Target> ser::SerializeTupleStruct - for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - -impl<'target, Target> ser::SerializeTupleVariant - for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - -impl<'target, Target> ser::SerializeMap for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_key(&mut self, - _key: &T) - -> Result<(), Error> { - unreachable!() - } - - fn serialize_value(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - -impl<'target, Target> ser::SerializeStruct for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - -impl<'target, Target> ser::SerializeStructVariant - for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result<(), Error> { - unreachable!() - } -} - enum PairState { WaitingForKey, WaitingForValue { key: Cow<'static, str> }, diff --git a/src/ser/part.rs b/src/ser/part.rs index a8654508..097504e0 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -1,4 +1,5 @@ use ser::Error; +use ser::void::VoidSerializer; use serde::ser; use std::str; @@ -36,13 +37,13 @@ pub trait Sink: Sized { impl ser::Serializer for PartSerializer { type Ok = S::Ok; type Error = Error; - type SerializeSeq = Self; - type SerializeTuple = Self; - type SerializeTupleStruct = Self; - type SerializeTupleVariant = Self; - type SerializeMap = Self; - type SerializeStruct = Self; - type SerializeStructVariant = Self; + type SerializeSeq = VoidSerializer; + type SerializeTuple = VoidSerializer; + type SerializeTupleStruct = VoidSerializer; + type SerializeTupleVariant = VoidSerializer; + type SerializeMap = VoidSerializer; + type SerializeStruct = VoidSerializer; + type SerializeStructVariant = VoidSerializer; fn serialize_bool(self, v: bool) -> Result { self.sink.serialize_bool(v) @@ -147,165 +148,62 @@ impl ser::Serializer for PartSerializer { self.sink.serialize_some(value) } - fn serialize_seq(self, _len: Option) -> Result { + fn serialize_seq(self, + _len: Option) + -> Result { Err(self.sink.unsupported()) } - fn serialize_seq_fixed_size(self, _len: usize) -> Result { + fn serialize_seq_fixed_size(self, + _len: usize) + -> Result { Err(self.sink.unsupported()) } - fn serialize_tuple(self, _len: usize) -> Result { + fn serialize_tuple(self, + _len: usize) + -> Result { Err(self.sink.unsupported()) } fn serialize_tuple_struct(self, _name: &'static str, _len: usize) - -> Result { + -> Result { Err(self.sink.unsupported()) } - fn serialize_tuple_variant(self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(self.sink.unsupported()) } - fn serialize_map(self, _len: Option) -> Result { + fn serialize_map(self, + _len: Option) + -> Result { Err(self.sink.unsupported()) } fn serialize_struct(self, _name: &'static str, _len: usize) - -> Result { + -> Result { Err(self.sink.unsupported()) } - fn serialize_struct_variant(self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_struct_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(self.sink.unsupported()) } } - -impl ser::SerializeSeq for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_element(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeTuple for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_element(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeTupleStruct for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeTupleVariant for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeMap for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_key(&mut self, - _key: &T) - -> Result<(), Error> { - unreachable!() - } - - fn serialize_value(&mut self, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeStruct for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} - -impl ser::SerializeStructVariant for PartSerializer { - type Ok = S::Ok; - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - unreachable!() - } - - fn end(self) -> Result { - unreachable!() - } -} diff --git a/src/ser/void.rs b/src/ser/void.rs new file mode 100644 index 00000000..4765bb77 --- /dev/null +++ b/src/ser/void.rs @@ -0,0 +1,122 @@ +use ser::Error; +use serde::ser; +use std::marker::PhantomData; +use void; + +pub struct VoidSerializer { + void: void::Void, + _marker: PhantomData, +} + +impl ser::SerializeSeq for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeTuple for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_element(&mut self, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeTupleStruct for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeTupleVariant for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeMap for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_key(&mut self, + _key: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn serialize_value(&mut self, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeStruct for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} + +impl ser::SerializeStructVariant for VoidSerializer { + type Ok = Ok; + type Error = Error; + + fn serialize_field(&mut self, + _key: &'static str, + _value: &T) + -> Result<(), Error> { + void::unreachable(self.void) + } + + fn end(self) -> Result { + void::unreachable(self.void) + } +} From 1d88bbb26b9caaa90993845042e21af444e9399a Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Jan 2017 23:56:15 +0100 Subject: [PATCH 19/95] Use itoa to not allocate a String to serialize an integer --- Cargo.toml | 1 + src/lib.rs | 1 + src/ser/part.rs | 28 ++++++++++++++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a68819a6..e7865a4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["serde", "serialization", "urlencoded"] test = false [dependencies] +itoa = "0.3.0" serde = "0.9.2" url = "1.0.0" void = "1.0.2" diff --git a/src/lib.rs b/src/lib.rs index 0c1a99e2..7a3be266 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ //! `x-www-form-urlencoded` meets Serde +extern crate itoa; #[macro_use] extern crate serde; extern crate url; diff --git a/src/ser/part.rs b/src/ser/part.rs index 097504e0..33811f4d 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -1,3 +1,4 @@ +use itoa; use ser::Error; use ser::void::VoidSerializer; use serde::ser; @@ -50,35 +51,35 @@ impl ser::Serializer for PartSerializer { } fn serialize_i8(self, v: i8) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_i16(self, v: i16) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_i32(self, v: i32) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_i64(self, v: i64) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_u8(self, v: u8) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_u16(self, v: u16) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_u32(self, v: u32) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_u64(self, v: u64) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_integer(v) } fn serialize_f32(self, v: f32) -> Result { @@ -207,3 +208,14 @@ impl ser::Serializer for PartSerializer { Err(self.sink.unsupported()) } } + +impl PartSerializer { + fn serialize_integer(self, value: I) -> Result + where I: itoa::Integer + { + let mut buf = [b'\0'; 20]; + let len = itoa::write(&mut buf[..], value).unwrap(); + let part = unsafe { str::from_utf8_unchecked(&buf[0..len]) }; + ser::Serializer::serialize_str(self, part) + } +} From 5625c254e55c767a1ec0235219c232f53dcf9e96 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 29 Jan 2017 00:14:57 +0100 Subject: [PATCH 20/95] Use dtoa to not allocate a String to serialize a float --- Cargo.toml | 1 + src/lib.rs | 1 + src/ser/part.rs | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e7865a4a..8566cc16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["serde", "serialization", "urlencoded"] test = false [dependencies] +dtoa = "0.4.0" itoa = "0.3.0" serde = "0.9.2" url = "1.0.0" diff --git a/src/lib.rs b/src/lib.rs index 7a3be266..8fefd77e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! `x-www-form-urlencoded` meets Serde extern crate itoa; +extern crate dtoa; #[macro_use] extern crate serde; extern crate url; diff --git a/src/ser/part.rs b/src/ser/part.rs index 33811f4d..049bacde 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -1,3 +1,4 @@ +use dtoa; use itoa; use ser::Error; use ser::void::VoidSerializer; @@ -83,11 +84,11 @@ impl ser::Serializer for PartSerializer { } fn serialize_f32(self, v: f32) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_floating(v) } fn serialize_f64(self, v: f64) -> Result { - self.sink.serialize_string(v.to_string()) + self.serialize_floating(v) } fn serialize_char(self, v: char) -> Result { @@ -218,4 +219,13 @@ impl PartSerializer { let part = unsafe { str::from_utf8_unchecked(&buf[0..len]) }; ser::Serializer::serialize_str(self, part) } + + fn serialize_floating(self, value: F) -> Result + where F: dtoa::Floating + { + let mut buf = [b'\0'; 24]; + let len = dtoa::write(&mut buf[..], value).unwrap(); + let part = unsafe { str::from_utf8_unchecked(&buf[0..len]) }; + ser::Serializer::serialize_str(self, part) + } } From f5b1ae88282adfc2fe2253e4cd51c6ba5eca0c54 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 29 Jan 2017 00:17:54 +0100 Subject: [PATCH 21/95] Do not forbid bool keys anymore Floats are supported so... --- src/ser/key.rs | 4 ---- src/ser/part.rs | 4 +--- src/ser/value.rs | 4 ---- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/ser/key.rs b/src/ser/key.rs index 149c8f65..6cbbff42 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -46,10 +46,6 @@ impl Sink for KeySink { type Ok = Ok; - fn serialize_bool(self, _value: bool) -> Result { - Err(self.unsupported()) - } - fn serialize_static_str(self, value: &'static str) -> Result { diff --git a/src/ser/part.rs b/src/ser/part.rs index 049bacde..e720314c 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -18,8 +18,6 @@ impl PartSerializer { pub trait Sink: Sized { type Ok; - fn serialize_bool(self, value: bool) -> Result; - fn serialize_static_str(self, value: &'static str) -> Result; @@ -48,7 +46,7 @@ impl ser::Serializer for PartSerializer { type SerializeStructVariant = VoidSerializer; fn serialize_bool(self, v: bool) -> Result { - self.sink.serialize_bool(v) + self.sink.serialize_static_str(if v { "true" } else { "false" }) } fn serialize_i8(self, v: i8) -> Result { diff --git a/src/ser/value.rs b/src/ser/value.rs index 34ea7d02..e4e1f2ce 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -30,10 +30,6 @@ impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> { type Ok = (); - fn serialize_bool(self, value: bool) -> Result { - self.serialize_static_str(if value { "true" } else { "false" }) - } - fn serialize_str(self, value: &str) -> Result<(), Error> { self.urlencoder.append_pair(self.key, value); Ok(()) From fba478f827f549a17daa1aa3d8fe7b6d39967d30 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 29 Jan 2017 10:07:28 +0100 Subject: [PATCH 22/95] Add bors configuration --- .travis.yml | 3 +++ bors.toml | 1 + 2 files changed, 4 insertions(+) create mode 100644 bors.toml diff --git a/.travis.yml b/.travis.yml index 4ecd9b6b..088c2e49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,6 @@ rust: - nightly - beta - stable +branches: + except: + - staging.tmp diff --git a/bors.toml b/bors.toml new file mode 100644 index 00000000..359f8947 --- /dev/null +++ b/bors.toml @@ -0,0 +1 @@ +status = ["continuous-integration/travis-ci/push"] From 3e9ebe4fd7428da26dd75e2cc6e5025c847c99e6 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 28 Jan 2017 17:12:19 +0100 Subject: [PATCH 23/95] Bump version to 0.4.0 --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8566cc16..87991d55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.3.0" +version = "0.4.0" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" diff --git a/README.md b/README.md index 2f0f1782..105393b7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate works with Cargo and can be found on ```toml [dependencies] -serde_urlencoded = "0.2.1" +serde_urlencoded = "0.4.0" ``` [crates.io]: https://crates.io/crates/serde_urlencoded @@ -34,7 +34,7 @@ issues](https://github.com/nox/serde_urlencoded/issues/new) as well. ## License -Serde is licensed under either of +serde_urlencoded is licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) @@ -46,5 +46,5 @@ at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. +for inclusion in serde_urlencoded by you, as defined in the Apache-2.0 license, +shall be dual licensed as above, without any additional terms or conditions. From bc8197c884e7a5dae25b6aedb02eac98145bee92 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 31 Jan 2017 10:42:51 +0100 Subject: [PATCH 24/95] Update serde to 0.9.3 and use serde::ser::Impossible --- Cargo.toml | 3 +- src/lib.rs | 3 +- src/ser/mod.rs | 9 ++-- src/ser/pair.rs | 49 +++++++++---------- src/ser/part.rs | 19 ++++---- src/ser/void.rs | 122 ------------------------------------------------ 6 files changed, 41 insertions(+), 164 deletions(-) delete mode 100644 src/ser/void.rs diff --git a/Cargo.toml b/Cargo.toml index 87991d55..99a1bc23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,5 @@ test = false [dependencies] dtoa = "0.4.0" itoa = "0.3.0" -serde = "0.9.2" +serde = "0.9.3" url = "1.0.0" -void = "1.0.2" diff --git a/src/lib.rs b/src/lib.rs index 8fefd77e..285a091f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,12 @@ //! `x-www-form-urlencoded` meets Serde +#![warn(unused_extern_crates)] + extern crate itoa; extern crate dtoa; #[macro_use] extern crate serde; extern crate url; -extern crate void; pub mod de; pub mod ser; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 50355fda..f36be4ff 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -4,7 +4,6 @@ mod key; mod pair; mod part; mod value; -mod void; use serde::ser; use std::borrow::Cow; @@ -102,21 +101,21 @@ pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { /// /// Never instantiated, tuples are not supported at top-level. pub struct TupleSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. pub struct TupleStructSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. pub struct TupleVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, } /// Map serializer. @@ -134,7 +133,7 @@ pub struct StructSerializer<'output, Target: 'output + UrlEncodedTarget> { /// /// Never instantiated, struct variants are not supported. pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: void::VoidSerializer<&'output mut UrlEncodedSerializer>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, } impl<'output, Target> ser::Serializer for Serializer<'output, Target> diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 743b3ddc..68156476 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -2,7 +2,6 @@ use ser::Error; use ser::key::KeySink; use ser::part::PartSerializer; use ser::value::ValueSink; -use ser::void::VoidSerializer; use serde::ser; use std::borrow::Cow; use std::mem; @@ -30,13 +29,13 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> { type Ok = (); type Error = Error; - type SerializeSeq = VoidSerializer<()>; + type SerializeSeq = ser::Impossible<(), Error>; type SerializeTuple = Self; - type SerializeTupleStruct = VoidSerializer<()>; - type SerializeTupleVariant = VoidSerializer<()>; - type SerializeMap = VoidSerializer<()>; - type SerializeStruct = VoidSerializer<()>; - type SerializeStructVariant = VoidSerializer<()>; + type SerializeTupleStruct = ser::Impossible<(), Error>; + type SerializeTupleVariant = ser::Impossible<(), Error>; + type SerializeMap = ser::Impossible<(), Error>; + type SerializeStruct = ser::Impossible<(), Error>; + type SerializeStructVariant = ser::Impossible<(), Error>; fn serialize_bool(self, _v: bool) -> Result<(), Error> { Err(Error::unsupported_pair()) @@ -140,13 +139,13 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_seq(self, _len: Option) - -> Result, Error> { + -> Result { Err(Error::unsupported_pair()) } fn serialize_seq_fixed_size(self, _len: usize) - -> Result, Error> { + -> Result { Err(Error::unsupported_pair()) } @@ -161,38 +160,40 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_tuple_struct(self, _name: &'static str, _len: usize) - -> Result, Error> { + -> Result { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant(self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result, Error> { + fn serialize_tuple_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(Error::unsupported_pair()) } fn serialize_map(self, _len: Option) - -> Result, Error> { + -> Result { Err(Error::unsupported_pair()) } fn serialize_struct(self, _name: &'static str, _len: usize) - -> Result, Error> { + -> Result { Err(Error::unsupported_pair()) } - fn serialize_struct_variant(self, - _name: &'static str, - _variant_index: usize, - _variant: &'static str, - _len: usize) - -> Result, Error> { + fn serialize_struct_variant + (self, + _name: &'static str, + _variant_index: usize, + _variant: &'static str, + _len: usize) + -> Result { Err(Error::unsupported_pair()) } } diff --git a/src/ser/part.rs b/src/ser/part.rs index e720314c..42653c01 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -1,7 +1,6 @@ use dtoa; use itoa; use ser::Error; -use ser::void::VoidSerializer; use serde::ser; use std::str; @@ -37,13 +36,13 @@ pub trait Sink: Sized { impl ser::Serializer for PartSerializer { type Ok = S::Ok; type Error = Error; - type SerializeSeq = VoidSerializer; - type SerializeTuple = VoidSerializer; - type SerializeTupleStruct = VoidSerializer; - type SerializeTupleVariant = VoidSerializer; - type SerializeMap = VoidSerializer; - type SerializeStruct = VoidSerializer; - type SerializeStructVariant = VoidSerializer; + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = ser::Impossible; + type SerializeStruct = ser::Impossible; + type SerializeStructVariant = ser::Impossible; fn serialize_bool(self, v: bool) -> Result { self.sink.serialize_static_str(if v { "true" } else { "false" }) @@ -210,7 +209,7 @@ impl ser::Serializer for PartSerializer { impl PartSerializer { fn serialize_integer(self, value: I) -> Result - where I: itoa::Integer + where I: itoa::Integer, { let mut buf = [b'\0'; 20]; let len = itoa::write(&mut buf[..], value).unwrap(); @@ -219,7 +218,7 @@ impl PartSerializer { } fn serialize_floating(self, value: F) -> Result - where F: dtoa::Floating + where F: dtoa::Floating, { let mut buf = [b'\0'; 24]; let len = dtoa::write(&mut buf[..], value).unwrap(); diff --git a/src/ser/void.rs b/src/ser/void.rs deleted file mode 100644 index 4765bb77..00000000 --- a/src/ser/void.rs +++ /dev/null @@ -1,122 +0,0 @@ -use ser::Error; -use serde::ser; -use std::marker::PhantomData; -use void; - -pub struct VoidSerializer { - void: void::Void, - _marker: PhantomData, -} - -impl ser::SerializeSeq for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_element(&mut self, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeTuple for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_element(&mut self, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeTupleStruct for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeTupleVariant for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_field(&mut self, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeMap for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_key(&mut self, - _key: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn serialize_value(&mut self, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeStruct for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} - -impl ser::SerializeStructVariant for VoidSerializer { - type Ok = Ok; - type Error = Error; - - fn serialize_field(&mut self, - _key: &'static str, - _value: &T) - -> Result<(), Error> { - void::unreachable(self.void) - } - - fn end(self) -> Result { - void::unreachable(self.void) - } -} From a2fb94e32d81770fc67acd273890d5595520d059 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 31 Jan 2017 10:57:10 +0100 Subject: [PATCH 25/95] Add a couple of categories --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 99a1bc23..d7f4eb68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" documentation = "https://docs.rs/serde_urlencoded" description = "`x-www-form-urlencoded` meets Serde" +categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] [lib] From b24505bcfed47b88c1f2aa13c8743aa4b4cd2c3f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 31 Jan 2017 10:57:22 +0100 Subject: [PATCH 26/95] Bump to 0.4.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d7f4eb68..e788d4e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.4.0" +version = "0.4.1" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 8839c6a86ce52eb28471ef491b280f9e91b023cd Mon Sep 17 00:00:00 2001 From: Arthur Skobara Date: Sun, 5 Feb 2017 10:37:15 +0700 Subject: [PATCH 27/95] Introduce de::from_reader --- src/de.rs | 14 ++++++++++++++ src/lib.rs | 2 +- tests/test_deserialize.rs | 25 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/test_deserialize.rs diff --git a/src/de.rs b/src/de.rs index 95208e9f..95999d08 100644 --- a/src/de.rs +++ b/src/de.rs @@ -4,6 +4,7 @@ use serde::de; pub use serde::de::value::Error; use serde::de::value::MapDeserializer; +use std::io::Read; use url::form_urlencoded::Parse as UrlEncodedParse; use url::form_urlencoded::parse; @@ -45,6 +46,19 @@ pub fn from_str(input: &str) -> Result { from_bytes(input.as_bytes()) } +/// Convenience function that reads all bytes from `reader` and deserializes +/// them with `from_bytes`. +pub fn from_reader(mut reader: R) -> Result + where T: de::Deserialize, R: Read +{ + let mut buf = vec![]; + reader.read_to_end(&mut buf) + .map_err(|e| { + de::Error::custom(format_args!("could not read input: {}", e)) + })?; + from_bytes(&buf) +} + /// A deserializer for the `application/x-www-form-urlencoded` format. /// /// * Supported top-level outputs are structs, maps and sequences of pairs, diff --git a/src/lib.rs b/src/lib.rs index 285a091f..db5f3a7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,5 +11,5 @@ extern crate url; pub mod de; pub mod ser; -pub use de::{Deserializer, from_bytes, from_str}; +pub use de::{Deserializer, from_bytes, from_str, from_reader}; pub use ser::{Serializer, to_string}; diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs new file mode 100644 index 00000000..eeb2ce62 --- /dev/null +++ b/tests/test_deserialize.rs @@ -0,0 +1,25 @@ +extern crate serde_urlencoded; + +#[test] +fn deserialize_bytes() { + let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; + + assert_eq!(serde_urlencoded::from_bytes(b"first=23&last=42"), + Ok(result)); +} + +#[test] +fn deserialize_str() { + let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; + + assert_eq!(serde_urlencoded::from_str("first=23&last=42"), + Ok(result)); +} + +#[test] +fn deserialize_reader() { + let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; + + assert_eq!(serde_urlencoded::from_reader(b"first=23&last=42" as &[_]), + Ok(result)); +} From a8def0d8656312b86e512fa6798f0ef09e7a3645 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 5 Feb 2017 14:45:48 +0100 Subject: [PATCH 28/95] Inline docs of reexports and bump version to 0.4.2 --- Cargo.toml | 5 ++++- README.md | 2 +- src/de.rs | 1 + src/lib.rs | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e788d4e8..a788d23e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.4.1" +version = "0.4.2" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" @@ -9,6 +9,9 @@ description = "`x-www-form-urlencoded` meets Serde" categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] +[badges] +travis-ci = {repository = "nox/serde_urlencoded"} + [lib] test = false diff --git a/README.md b/README.md index 105393b7..316add18 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate works with Cargo and can be found on ```toml [dependencies] -serde_urlencoded = "0.4.0" +serde_urlencoded = "0.4.2" ``` [crates.io]: https://crates.io/crates/serde_urlencoded diff --git a/src/de.rs b/src/de.rs index 95999d08..623bb491 100644 --- a/src/de.rs +++ b/src/de.rs @@ -2,6 +2,7 @@ use serde::de; +#[doc(inline)] pub use serde::de::value::Error; use serde::de::value::MapDeserializer; use std::io::Read; diff --git a/src/lib.rs b/src/lib.rs index db5f3a7c..bf7ad591 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,5 +11,7 @@ extern crate url; pub mod de; pub mod ser; -pub use de::{Deserializer, from_bytes, from_str, from_reader}; +#[doc(inline)] +pub use de::{Deserializer, from_bytes, from_reader, from_str}; +#[doc(inline)] pub use ser::{Serializer, to_string}; From f122a88561b6bea9d6e56c53b0946fbc323e2432 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 6 May 2017 10:43:25 +0200 Subject: [PATCH 29/95] Reformat de --- src/de.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/de.rs b/src/de.rs index 623bb491..0ab9b078 100644 --- a/src/de.rs +++ b/src/de.rs @@ -50,7 +50,8 @@ pub fn from_str(input: &str) -> Result { /// Convenience function that reads all bytes from `reader` and deserializes /// them with `from_bytes`. pub fn from_reader(mut reader: R) -> Result - where T: de::Deserialize, R: Read + where T: de::Deserialize, + R: Read, { let mut buf = vec![]; reader.read_to_end(&mut buf) From 7ddde33a33b1f295ec8e4a2edd74487353210bd5 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 6 May 2017 10:59:42 +0200 Subject: [PATCH 30/95] Have a custom type for deserialising values (fixes #16) This lets us handle Option values correctly. --- src/de.rs | 89 +++++++++++++++++++++++++++++++++++++-- tests/test_deserialize.rs | 9 ++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/de.rs b/src/de.rs index 0ab9b078..10015487 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,11 +1,14 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. use serde::de; +use serde::de::value::{MapDeserializer, ValueDeserializer as SerdeValueDeserializer}; #[doc(inline)] pub use serde::de::value::Error; -use serde::de::value::MapDeserializer; +use std::borrow::Cow; use std::io::Read; +use std::iter::Map; +use std::marker::PhantomData; use url::form_urlencoded::Parse as UrlEncodedParse; use url::form_urlencoded::parse; @@ -71,13 +74,18 @@ pub fn from_reader(mut reader: R) -> Result /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'a> { - inner: MapDeserializer, Error>, + inner: MapDeserializer, + fn((Cow<'a, str>, Cow<'a, str>)) + -> (Cow<'a, str>, Value<'a>)>, + Error>, } impl<'a> Deserializer<'a> { /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'a>) -> Self { - Deserializer { inner: MapDeserializer::new(parser) } + Deserializer { + inner: MapDeserializer::new(parser.map(Value::wrap_pair)), + } } } @@ -140,3 +148,78 @@ impl<'a> de::Deserializer for Deserializer<'a> { ignored_any } } + +struct Value<'a>(Cow<'a, str>); + +impl<'a> Value<'a> { + fn wrap_pair((k, v): (Cow<'a, str>, Cow<'a, str>)) -> (Cow<'a, str>, Self) { + (k, Value(v)) + } +} + +impl<'a, E> SerdeValueDeserializer for Value<'a> + where E: de::Error, +{ + type Deserializer = ValueDeserializer<'a, E>; + + fn into_deserializer(self) -> Self::Deserializer { + ValueDeserializer { + value: self.0, + marker: PhantomData, + } + } +} + +struct ValueDeserializer<'a, E> { + value: Cow<'a, str>, + marker: PhantomData, +} + +impl<'a, E> de::Deserializer for ValueDeserializer<'a, E> + where E: de::Error, +{ + type Error = E; + + fn deserialize(self, visitor: V) -> Result + where V: de::Visitor, + { + self.value.into_deserializer().deserialize(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where V: de::Visitor, + { + visitor.visit_some(self.value.into_deserializer()) + } + + forward_to_deserialize! { + bool + u8 + u16 + u32 + u64 + i8 + i16 + i32 + i64 + f32 + f64 + char + str + string + unit + bytes + byte_buf + unit_struct + newtype_struct + tuple_struct + struct + struct_field + tuple + enum + ignored_any + seq + seq_fixed_size + map + } +} diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index eeb2ce62..bd92ba9e 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -23,3 +23,12 @@ fn deserialize_reader() { assert_eq!(serde_urlencoded::from_reader(b"first=23&last=42" as &[_]), Ok(result)); } + +#[test] +fn deserialize_option() { + let result = vec![ + ("first".to_owned(), Some(23)), + ("last".to_owned(), Some(42)), + ]; + assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); +} From 81aad8e8bdf0b85551b43fa806e295cfe0364131 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 6 May 2017 11:06:12 +0200 Subject: [PATCH 31/95] Bump version to 0.4.3 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a788d23e..c356ece7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.4.2" +version = "0.4.3" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From abb8d81f9f1e515df5ed12a5a3e2a262e1ec0323 Mon Sep 17 00:00:00 2001 From: Ted Driggs Date: Thu, 20 Apr 2017 15:49:30 -0700 Subject: [PATCH 32/95] Update to serde 1.0.0 --- Cargo.toml | 4 +- src/de.rs | 145 ++++++++++++++++++++++++------------------------ src/ser/mod.rs | 38 ++++++------- src/ser/pair.rs | 14 ++--- src/ser/part.rs | 15 ++--- 5 files changed, 100 insertions(+), 116 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c356ece7..d293bff7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.4.3" +version = "0.5.0" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" @@ -18,5 +18,5 @@ test = false [dependencies] dtoa = "0.4.0" itoa = "0.3.0" -serde = "0.9.3" +serde = "1.0.0" url = "1.0.0" diff --git a/src/de.rs b/src/de.rs index 10015487..9eec6a94 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,16 +1,15 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. -use serde::de; -use serde::de::value::{MapDeserializer, ValueDeserializer as SerdeValueDeserializer}; +use serde::de::{self, IntoDeserializer}; + +use serde::de::value::MapDeserializer; +use std::borrow::Cow; +use std::io::Read; +use url::form_urlencoded::Parse as UrlEncodedParse; +use url::form_urlencoded::parse; #[doc(inline)] pub use serde::de::value::Error; -use std::borrow::Cow; -use std::io::Read; -use std::iter::Map; -use std::marker::PhantomData; -use url::form_urlencoded::Parse as UrlEncodedParse; -use url::form_urlencoded::parse; /// Deserializes a `application/x-wwww-url-encoded` value from a `&[u8]`. /// @@ -27,7 +26,9 @@ use url::form_urlencoded::parse; /// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), /// Ok(meal)); /// ``` -pub fn from_bytes(input: &[u8]) -> Result { +pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result + where T: de::Deserialize<'de>, +{ T::deserialize(Deserializer::new(parse(input))) } @@ -46,14 +47,16 @@ pub fn from_bytes(input: &[u8]) -> Result { /// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), /// Ok(meal)); /// ``` -pub fn from_str(input: &str) -> Result { +pub fn from_str<'de, T>(input: &'de str) -> Result + where T: de::Deserialize<'de>, +{ from_bytes(input.as_bytes()) } /// Convenience function that reads all bytes from `reader` and deserializes /// them with `from_bytes`. pub fn from_reader(mut reader: R) -> Result - where T: de::Deserialize, + where T: de::DeserializeOwned, R: Read, { let mut buf = vec![]; @@ -73,53 +76,41 @@ pub fn from_reader(mut reader: R) -> Result /// /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. -pub struct Deserializer<'a> { - inner: MapDeserializer, - fn((Cow<'a, str>, Cow<'a, str>)) - -> (Cow<'a, str>, Value<'a>)>, - Error>, +pub struct Deserializer<'de> { + inner: MapDeserializer<'de, PartIterator<'de>, Error>, } -impl<'a> Deserializer<'a> { +impl<'de> Deserializer<'de> { /// Returns a new `Deserializer`. - pub fn new(parser: UrlEncodedParse<'a>) -> Self { + pub fn new(parser: UrlEncodedParse<'de>) -> Self { Deserializer { - inner: MapDeserializer::new(parser.map(Value::wrap_pair)), + inner: MapDeserializer::new(PartIterator(parser)), } } } -impl<'a> de::Deserializer for Deserializer<'a> { +impl<'de> de::Deserializer<'de> for Deserializer<'de> { type Error = Error; - fn deserialize(self, visitor: V) -> Result - where V: de::Visitor, + fn deserialize_any(self, visitor: V) -> Result + where V: de::Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_map(self, visitor: V) -> Result - where V: de::Visitor, + where V: de::Visitor<'de>, { visitor.visit_map(self.inner) } fn deserialize_seq(self, visitor: V) -> Result - where V: de::Visitor, + where V: de::Visitor<'de>, { visitor.visit_seq(self.inner) } - fn deserialize_seq_fixed_size(self, - _len: usize, - visitor: V) - -> Result - where V: de::Visitor, - { - visitor.visit_seq(self.inner) - } - - forward_to_deserialize! { + forward_to_deserialize_any! { bool u8 u16 @@ -142,68 +133,65 @@ impl<'a> de::Deserializer for Deserializer<'a> { newtype_struct tuple_struct struct - struct_field + identifier tuple enum ignored_any } } -struct Value<'a>(Cow<'a, str>); +struct PartIterator<'de>(UrlEncodedParse<'de>); -impl<'a> Value<'a> { - fn wrap_pair((k, v): (Cow<'a, str>, Cow<'a, str>)) -> (Cow<'a, str>, Self) { - (k, Value(v)) +impl<'de> Iterator for PartIterator<'de> { + type Item = (Part<'de>, Part<'de>); + + fn next(&mut self) -> Option { + self.0.next().map(|(k, v)| (Part(k), Part(v))) } } -impl<'a, E> SerdeValueDeserializer for Value<'a> - where E: de::Error, +struct Part<'de>(Cow<'de, str>); + +impl<'de> IntoDeserializer<'de> for Part<'de> { - type Deserializer = ValueDeserializer<'a, E>; + type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { - ValueDeserializer { - value: self.0, - marker: PhantomData, - } + self } } -struct ValueDeserializer<'a, E> { - value: Cow<'a, str>, - marker: PhantomData, +macro_rules! forward_parsed_value { + ($($ty:ident => $method:ident,)*) => { + $( + fn $method(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + match self.0.parse::<$ty>() { + Ok(val) => val.into_deserializer().$method(visitor), + Err(e) => Err(de::Error::custom(e)) + } + } + )* + } } -impl<'a, E> de::Deserializer for ValueDeserializer<'a, E> - where E: de::Error, -{ - type Error = E; +impl<'de> de::Deserializer<'de> for Part<'de> { + type Error = Error; - fn deserialize(self, visitor: V) -> Result - where V: de::Visitor, + fn deserialize_any(self, visitor: V) -> Result + where V: de::Visitor<'de>, { - self.value.into_deserializer().deserialize(visitor) + self.0.into_deserializer().deserialize_any(visitor) } fn deserialize_option(self, visitor: V) -> Result - where V: de::Visitor, + where V: de::Visitor<'de>, { - visitor.visit_some(self.value.into_deserializer()) + visitor.visit_some(self) } - forward_to_deserialize! { - bool - u8 - u16 - u32 - u64 - i8 - i16 - i32 - i64 - f32 - f64 + forward_to_deserialize_any! { char str string @@ -214,12 +202,25 @@ impl<'a, E> de::Deserializer for ValueDeserializer<'a, E> newtype_struct tuple_struct struct - struct_field + identifier tuple enum ignored_any seq - seq_fixed_size map } + + forward_parsed_value! { + bool => deserialize_bool, + u8 => deserialize_u8, + u16 => deserialize_u16, + u32 => deserialize_u32, + u64 => deserialize_u64, + i8 => deserialize_i8, + i16 => deserialize_i16, + i32 => deserialize_i32, + i64 => deserialize_i64, + f32 => deserialize_f32, + f64 => deserialize_f64, + } } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index f36be4ff..7d6bab82 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -27,7 +27,7 @@ use url::form_urlencoded::Target as UrlEncodedTarget; /// serde_urlencoded::to_string(meal), /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); /// ``` -pub fn to_string(input: &T) -> Result { +pub fn to_string(input: T) -> Result { let mut urlencoder = UrlEncodedSerializer::new("".to_owned()); input.serialize(Serializer::new(&mut urlencoder))?; Ok(urlencoder.finish()) @@ -99,9 +99,9 @@ pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { /// Tuple serializer. /// -/// Never instantiated, tuples are not supported at top-level. -pub struct TupleSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, +/// Mostly used for arrays. +pub struct TupleSerializer<'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer, } /// Tuple struct serializer. @@ -234,7 +234,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> /// Returns an error. fn serialize_unit_variant(self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str) -> Result { Err(Error::top_level()) @@ -253,7 +253,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_newtype_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _value: &T) -> Result { @@ -280,18 +280,11 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> Ok(SeqSerializer { urlencoder: self.urlencoder }) } - /// Serializes a sequence, given length is ignored. - fn serialize_seq_fixed_size(self, - _len: usize) - -> Result { - Ok(SeqSerializer { urlencoder: self.urlencoder }) - } - /// Returns an error. fn serialize_tuple(self, _len: usize) -> Result { - Err(Error::top_level()) + Ok(TupleSerializer { urlencoder: self.urlencoder }) } /// Returns an error. @@ -306,7 +299,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_tuple_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { @@ -335,7 +328,7 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> fn serialize_struct_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { @@ -369,16 +362,17 @@ impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> fn serialize_element(&mut self, value: &T) -> Result<(), Error> { - self.inner.serialize_element(value) + value.serialize(pair::PairSerializer::new(self.urlencoder)) } fn end(self) -> Result { - self.inner.end() + Ok(self.urlencoder) } } impl<'output, Target> ser::SerializeTupleStruct - for TupleStructSerializer<'output, Target> + for + TupleStructSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; @@ -396,7 +390,8 @@ impl<'output, Target> ser::SerializeTupleStruct } impl<'output, Target> ser::SerializeTupleVariant - for TupleVariantSerializer<'output, Target> + for + TupleVariantSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; @@ -480,7 +475,8 @@ impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> } impl<'output, Target> ser::SerializeStructVariant - for StructVariantSerializer<'output, Target> + for + StructVariantSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 68156476..8fedcc0a 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -103,7 +103,7 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_unit_variant(self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str) -> Result<(), Error> { Err(Error::unsupported_pair()) @@ -120,7 +120,7 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_newtype_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _value: &T) -> Result<(), Error> { @@ -143,12 +143,6 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_seq_fixed_size(self, - _len: usize) - -> Result { - Err(Error::unsupported_pair()) - } - fn serialize_tuple(self, len: usize) -> Result { if len == 2 { Ok(self) @@ -167,7 +161,7 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_tuple_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { @@ -190,7 +184,7 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> fn serialize_struct_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { diff --git a/src/ser/part.rs b/src/ser/part.rs index 42653c01..36ce1414 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -113,7 +113,7 @@ impl ser::Serializer for PartSerializer { fn serialize_unit_variant(self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, variant: &'static str) -> Result { self.sink.serialize_static_str(variant.into()) @@ -130,7 +130,7 @@ impl ser::Serializer for PartSerializer { fn serialize_newtype_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _value: &T) -> Result { @@ -153,13 +153,6 @@ impl ser::Serializer for PartSerializer { Err(self.sink.unsupported()) } - - fn serialize_seq_fixed_size(self, - _len: usize) - -> Result { - Err(self.sink.unsupported()) - } - fn serialize_tuple(self, _len: usize) -> Result { @@ -176,7 +169,7 @@ impl ser::Serializer for PartSerializer { fn serialize_tuple_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { @@ -199,7 +192,7 @@ impl ser::Serializer for PartSerializer { fn serialize_struct_variant (self, _name: &'static str, - _variant_index: usize, + _variant_index: u32, _variant: &'static str, _len: usize) -> Result { From ecb91cfcd7ba2d893b0697be6631109a14e71666 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Sat, 20 May 2017 22:30:50 -0700 Subject: [PATCH 33/95] Deserialize () from input without key/value pairs. --- Cargo.toml | 2 +- README.md | 2 +- src/de.rs | 8 +++++++- tests/test_deserialize.rs | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d293bff7..2d4ef14e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.0" +version = "0.5.1" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" diff --git a/README.md b/README.md index 316add18..e55a86c2 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This crate works with Cargo and can be found on ```toml [dependencies] -serde_urlencoded = "0.4.2" +serde_urlencoded = "0.5.1" ``` [crates.io]: https://crates.io/crates/serde_urlencoded diff --git a/src/de.rs b/src/de.rs index 9eec6a94..137093d2 100644 --- a/src/de.rs +++ b/src/de.rs @@ -110,6 +110,13 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { visitor.visit_seq(self.inner) } + fn deserialize_unit(self, visitor: V) -> Result + where V: de::Visitor<'de>, + { + self.inner.end()?; + visitor.visit_unit() + } + forward_to_deserialize_any! { bool u8 @@ -125,7 +132,6 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { char str string - unit option bytes byte_buf diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index bd92ba9e..d2fb5fef 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -32,3 +32,11 @@ fn deserialize_option() { ]; assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); } + +#[test] +fn deserialize_unit() { + assert_eq!(serde_urlencoded::from_str(""), Ok(())); + assert_eq!(serde_urlencoded::from_str("&"), Ok(())); + assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); + assert!(serde_urlencoded::from_str::<()>("first=23").is_err()); +} From b4804ad95a0d39f1d6bcc4e923dcd7936c05d8f2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 19 Mar 2018 09:53:30 -0400 Subject: [PATCH 34/95] Bump itoa dep to 0.4.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2d4ef14e..b7e78c96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,6 @@ test = false [dependencies] dtoa = "0.4.0" -itoa = "0.3.0" +itoa = "0.4.0" serde = "1.0.0" url = "1.0.0" From 147bc9d93f1a4c2b35e950ab0b033ce2f5bff0a1 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 15 May 2018 22:19:04 +0200 Subject: [PATCH 35/95] Bump version to 0.5.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b7e78c96..9b8c13ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.1" +version = "0.5.2" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 4d220818f758a0797f754c8ca33b117ee981d5e5 Mon Sep 17 00:00:00 2001 From: Shaun Mangelsdorf Date: Tue, 13 Feb 2018 11:50:58 +1000 Subject: [PATCH 36/95] Implement deserialization into unit enums --- Cargo.toml | 5 ++- src/de.rs | 67 +++++++++++++++++++++++++++++++++++++-- tests/test_deserialize.rs | 20 ++++++++++++ tests/test_serialize.rs | 16 ++++++++++ 4 files changed, 105 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9b8c13ee..da1bdac6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.2" +version = "0.5.3" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" @@ -20,3 +20,6 @@ dtoa = "0.4.0" itoa = "0.4.0" serde = "1.0.0" url = "1.0.0" + +[dev-dependencies] +serde_derive = "1.0" diff --git a/src/de.rs b/src/de.rs index 137093d2..eeb5ff36 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,7 +1,7 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. use serde::de::{self, IntoDeserializer}; - +use serde::de::Error as de_Error; use serde::de::value::MapDeserializer; use std::borrow::Cow; use std::io::Read; @@ -197,6 +197,17 @@ impl<'de> de::Deserializer<'de> for Part<'de> { visitor.visit_some(self) } + fn deserialize_enum( + self, + _name: &'static str, + _variants: &'static [&'static str], + visitor: V, + ) -> Result + where V: de::Visitor<'de>, + { + visitor.visit_enum(ValueEnumAccess(self.0)) + } + forward_to_deserialize_any! { char str @@ -210,7 +221,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { struct identifier tuple - enum ignored_any seq map @@ -230,3 +240,56 @@ impl<'de> de::Deserializer<'de> for Part<'de> { f64 => deserialize_f64, } } + +struct ValueEnumAccess<'de>(Cow<'de, str>); + +impl<'de> de::EnumAccess<'de> for ValueEnumAccess<'de> { + type Error = Error; + type Variant = UnitOnlyVariantAccess; + + fn variant_seed( + self, + seed: V, + ) -> Result<(V::Value, Self::Variant), Self::Error> + where V: de::DeserializeSeed<'de>, + { + let variant = seed.deserialize(self.0.into_deserializer())?; + Ok((variant, UnitOnlyVariantAccess)) + } +} + +struct UnitOnlyVariantAccess; + +impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed(self, _seed: T) -> Result + where T: de::DeserializeSeed<'de>, + { + Err(Error::custom("expected unit variant")) + } + + fn tuple_variant( + self, + _len: usize, + _visitor: V, + ) -> Result + where V: de::Visitor<'de>, + { + Err(Error::custom("expected unit variant")) + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result + where V: de::Visitor<'de>, + { + Err(Error::custom("expected unit variant")) + } +} diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index d2fb5fef..ee19374c 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -1,4 +1,6 @@ extern crate serde_urlencoded; +#[macro_use] +extern crate serde_derive; #[test] fn deserialize_bytes() { @@ -40,3 +42,21 @@ fn deserialize_unit() { assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); assert!(serde_urlencoded::from_str::<()>("first=23").is_err()); } + +#[derive(Deserialize, Debug, PartialEq, Eq)] +enum X { + A, + B, + C, +} + +#[test] +fn deserialize_unit_enum() { + let result = vec![ + ("one".to_owned(), X::A), + ("two".to_owned(), X::B), + ("three".to_owned(), X::C) + ]; + + assert_eq!(serde_urlencoded::from_str("one=A&two=B&three=C"), Ok(result)); +} diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index e4e70eeb..3905ce6b 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -1,4 +1,6 @@ extern crate serde_urlencoded; +#[macro_use] +extern crate serde_derive; #[test] fn serialize_option_map_int() { @@ -32,3 +34,17 @@ fn serialize_map_bool() { assert_eq!(serde_urlencoded::to_string(params), Ok("one=true&two=false".to_owned())); } + +#[derive(Serialize)] +enum X { + A, + B, + C, +} + +#[test] +fn serialize_unit_enum() { + let params = &[("one", X::A), ("two", X::B), ("three", X::C)]; + assert_eq!(serde_urlencoded::to_string(params), + Ok("one=A&two=B&three=C".to_owned())); +} From 0ecc730e64ebf9fc12e81fe2f580634b338086ab Mon Sep 17 00:00:00 2001 From: Sam Sieber Date: Mon, 19 Nov 2018 08:59:04 -0700 Subject: [PATCH 37/95] Fix struct newtype deserialization (and add tests) --- src/de.rs | 11 ++++++++++- tests/test_deserialize.rs | 11 +++++++++++ tests/test_serialize.rs | 12 ++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/de.rs b/src/de.rs index eeb5ff36..46b640ff 100644 --- a/src/de.rs +++ b/src/de.rs @@ -208,6 +208,16 @@ impl<'de> de::Deserializer<'de> for Part<'de> { visitor.visit_enum(ValueEnumAccess(self.0)) } + fn deserialize_newtype_struct( + self, + _name: &'static str, + visitor: V, + ) -> Result + where V: de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + forward_to_deserialize_any! { char str @@ -216,7 +226,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { bytes byte_buf unit_struct - newtype_struct tuple_struct struct identifier diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index ee19374c..a0065066 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -2,6 +2,17 @@ extern crate serde_urlencoded; #[macro_use] extern crate serde_derive; +#[derive(Deserialize, Debug, PartialEq)] +struct NewType(T); + +#[test] +fn deserialize_newtype_i32() { + let result = vec![("field".to_owned(), NewType(11))]; + + assert_eq!(serde_urlencoded::from_str("field=11"), + Ok(result)); +} + #[test] fn deserialize_bytes() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 3905ce6b..5f2b95ef 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -2,6 +2,18 @@ extern crate serde_urlencoded; #[macro_use] extern crate serde_derive; +#[derive(Serialize)] +struct NewType(T); + +#[test] +fn serialize_newtype_i32() { + let params = &[("field", Some(NewType(11))),]; + assert_eq!( + serde_urlencoded::to_string(params), + Ok("field=11".to_owned()) + ); +} + #[test] fn serialize_option_map_int() { let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; From 8f829ac1b4f07cd7854e13c7776ac9a830c8ccf3 Mon Sep 17 00:00:00 2001 From: Sam Sieber Date: Mon, 19 Nov 2018 09:12:33 -0700 Subject: [PATCH 38/95] Bump version to 0.5.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index da1bdac6..a82d29bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.3" +version = "0.5.4" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 92eadc25bed164799d25f970f290302661e8d535 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 16 Apr 2019 11:15:32 +0200 Subject: [PATCH 39/95] Reformat --- rustfmt.toml | 2 - src/de.rs | 63 ++++++---- src/lib.rs | 6 +- src/ser/key.rs | 19 +-- src/ser/mod.rs | 239 +++++++++++++++++++++----------------- src/ser/pair.rs | 120 ++++++++++--------- src/ser/part.rs | 133 +++++++++++---------- src/ser/value.rs | 25 ++-- tests/test_deserialize.rs | 25 ++-- tests/test_serialize.rs | 39 ++++--- 10 files changed, 379 insertions(+), 292 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 70b05dfe..2b7608b3 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,7 +1,5 @@ match_block_trailing_comma = true max_width = 80 newline_style = "Unix" -reorder_imported_names = true reorder_imports = true use_try_shorthand = true -where_trailing_comma = true diff --git a/src/de.rs b/src/de.rs index 46b640ff..bee94a92 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,12 +1,12 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. -use serde::de::{self, IntoDeserializer}; -use serde::de::Error as de_Error; use serde::de::value::MapDeserializer; +use serde::de::Error as de_Error; +use serde::de::{self, IntoDeserializer}; use std::borrow::Cow; use std::io::Read; -use url::form_urlencoded::Parse as UrlEncodedParse; use url::form_urlencoded::parse; +use url::form_urlencoded::Parse as UrlEncodedParse; #[doc(inline)] pub use serde::de::value::Error; @@ -27,7 +27,8 @@ pub use serde::de::value::Error; /// Ok(meal)); /// ``` pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result - where T: de::Deserialize<'de>, +where + T: de::Deserialize<'de>, { T::deserialize(Deserializer::new(parse(input))) } @@ -48,7 +49,8 @@ pub fn from_bytes<'de, T>(input: &'de [u8]) -> Result /// Ok(meal)); /// ``` pub fn from_str<'de, T>(input: &'de str) -> Result - where T: de::Deserialize<'de>, +where + T: de::Deserialize<'de>, { from_bytes(input.as_bytes()) } @@ -56,14 +58,14 @@ pub fn from_str<'de, T>(input: &'de str) -> Result /// Convenience function that reads all bytes from `reader` and deserializes /// them with `from_bytes`. pub fn from_reader(mut reader: R) -> Result - where T: de::DeserializeOwned, - R: Read, +where + T: de::DeserializeOwned, + R: Read, { let mut buf = vec![]; - reader.read_to_end(&mut buf) - .map_err(|e| { - de::Error::custom(format_args!("could not read input: {}", e)) - })?; + reader.read_to_end(&mut buf).map_err(|e| { + de::Error::custom(format_args!("could not read input: {}", e)) + })?; from_bytes(&buf) } @@ -93,25 +95,29 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_map(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { visitor.visit_map(self.inner) } fn deserialize_seq(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { visitor.visit_seq(self.inner) } fn deserialize_unit(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { self.inner.end()?; visitor.visit_unit() @@ -158,8 +164,7 @@ impl<'de> Iterator for PartIterator<'de> { struct Part<'de>(Cow<'de, str>); -impl<'de> IntoDeserializer<'de> for Part<'de> -{ +impl<'de> IntoDeserializer<'de> for Part<'de> { type Deserializer = Self; fn into_deserializer(self) -> Self::Deserializer { @@ -186,13 +191,15 @@ impl<'de> de::Deserializer<'de> for Part<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { self.0.into_deserializer().deserialize_any(visitor) } fn deserialize_option(self, visitor: V) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { visitor.visit_some(self) } @@ -203,7 +210,8 @@ impl<'de> de::Deserializer<'de> for Part<'de> { _variants: &'static [&'static str], visitor: V, ) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { visitor.visit_enum(ValueEnumAccess(self.0)) } @@ -213,7 +221,8 @@ impl<'de> de::Deserializer<'de> for Part<'de> { _name: &'static str, visitor: V, ) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { visitor.visit_newtype_struct(self) } @@ -260,7 +269,8 @@ impl<'de> de::EnumAccess<'de> for ValueEnumAccess<'de> { self, seed: V, ) -> Result<(V::Value, Self::Variant), Self::Error> - where V: de::DeserializeSeed<'de>, + where + V: de::DeserializeSeed<'de>, { let variant = seed.deserialize(self.0.into_deserializer())?; Ok((variant, UnitOnlyVariantAccess)) @@ -277,7 +287,8 @@ impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { } fn newtype_variant_seed(self, _seed: T) -> Result - where T: de::DeserializeSeed<'de>, + where + T: de::DeserializeSeed<'de>, { Err(Error::custom("expected unit variant")) } @@ -287,7 +298,8 @@ impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { _len: usize, _visitor: V, ) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { Err(Error::custom("expected unit variant")) } @@ -297,7 +309,8 @@ impl<'de> de::VariantAccess<'de> for UnitOnlyVariantAccess { _fields: &'static [&'static str], _visitor: V, ) -> Result - where V: de::Visitor<'de>, + where + V: de::Visitor<'de>, { Err(Error::custom("expected unit variant")) } diff --git a/src/lib.rs b/src/lib.rs index bf7ad591..776ae54a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,8 @@ #![warn(unused_extern_crates)] -extern crate itoa; extern crate dtoa; +extern crate itoa; #[macro_use] extern crate serde; extern crate url; @@ -12,6 +12,6 @@ pub mod de; pub mod ser; #[doc(inline)] -pub use de::{Deserializer, from_bytes, from_reader, from_str}; +pub use de::{from_bytes, from_reader, from_str, Deserializer}; #[doc(inline)] -pub use ser::{Serializer, to_string}; +pub use ser::{to_string, Serializer}; diff --git a/src/ser/key.rs b/src/ser/key.rs index 6cbbff42..2a2e63ac 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -1,5 +1,5 @@ -use ser::Error; use ser::part::Sink; +use ser::Error; use serde::Serialize; use std::borrow::Cow; use std::ops::Deref; @@ -34,7 +34,8 @@ pub struct KeySink { } impl KeySink - where End: for<'key> FnOnce(Key<'key>) -> Result +where + End: for<'key> FnOnce(Key<'key>) -> Result, { pub fn new(end: End) -> Self { KeySink { end: end } @@ -42,13 +43,12 @@ impl KeySink } impl Sink for KeySink - where End: for<'key> FnOnce(Key<'key>) -> Result +where + End: for<'key> FnOnce(Key<'key>) -> Result, { type Ok = Ok; - fn serialize_static_str(self, - value: &'static str) - -> Result { + fn serialize_static_str(self, value: &'static str) -> Result { (self.end)(Key::Static(value)) } @@ -64,9 +64,10 @@ impl Sink for KeySink Err(self.unsupported()) } - fn serialize_some(self, - _value: &T) - -> Result { + fn serialize_some( + self, + _value: &T, + ) -> Result { Err(self.unsupported()) } diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 7d6bab82..633f1faa 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -49,7 +49,9 @@ pub struct Serializer<'output, Target: 'output + UrlEncodedTarget> { impl<'output, Target: 'output + UrlEncodedTarget> Serializer<'output, Target> { /// Returns a new `Serializer`. pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { - Serializer { urlencoder: urlencoder } + Serializer { + urlencoder: urlencoder, + } } } @@ -137,7 +139,8 @@ pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { } impl<'output, Target> ser::Serializer for Serializer<'output, Target> - where Target: 'output + UrlEncodedTarget, +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; @@ -225,38 +228,40 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Returns an error. - fn serialize_unit_struct(self, - _name: &'static str) - -> Result { + fn serialize_unit_struct( + self, + _name: &'static str, + ) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_unit_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str) - -> Result { + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result { Err(Error::top_level()) } /// Serializes the inner value, ignoring the newtype name. - fn serialize_newtype_struct - (self, - _name: &'static str, - value: &T) - -> Result { + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &T, + ) -> Result { value.serialize(self) } /// Returns an error. - fn serialize_newtype_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T) - -> Result { + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result { Err(Error::top_level()) } @@ -266,50 +271,58 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Serializes the given value. - fn serialize_some - (self, - value: &T) - -> Result { + fn serialize_some( + self, + value: &T, + ) -> Result { value.serialize(self) } /// Serialize a sequence, given length (if any) is ignored. - fn serialize_seq(self, - _len: Option) - -> Result { - Ok(SeqSerializer { urlencoder: self.urlencoder }) + fn serialize_seq( + self, + _len: Option, + ) -> Result { + Ok(SeqSerializer { + urlencoder: self.urlencoder, + }) } /// Returns an error. - fn serialize_tuple(self, - _len: usize) - -> Result { - Ok(TupleSerializer { urlencoder: self.urlencoder }) + fn serialize_tuple( + self, + _len: usize, + ) -> Result { + Ok(TupleSerializer { + urlencoder: self.urlencoder, + }) } /// Returns an error. - fn serialize_tuple_struct(self, - _name: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_tuple_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(Error::top_level()) } /// Serializes a map, given length is ignored. - fn serialize_map(self, - _len: Option) - -> Result { + fn serialize_map( + self, + _len: Option, + ) -> Result { Ok(MapSerializer { urlencoder: self.urlencoder, key: None, @@ -317,34 +330,39 @@ impl<'output, Target> ser::Serializer for Serializer<'output, Target> } /// Serializes a struct, given length is ignored. - fn serialize_struct(self, - _name: &'static str, - _len: usize) - -> Result { - Ok(StructSerializer { urlencoder: self.urlencoder }) + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Ok(StructSerializer { + urlencoder: self.urlencoder, + }) } /// Returns an error. - fn serialize_struct_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(Error::top_level()) } } impl<'output, Target> ser::SerializeSeq for SeqSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_element(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Error> { value.serialize(pair::PairSerializer::new(self.urlencoder)) } @@ -354,14 +372,16 @@ impl<'output, Target> ser::SerializeSeq for SeqSerializer<'output, Target> } impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_element(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Error> { value.serialize(pair::PairSerializer::new(self.urlencoder)) } @@ -371,16 +391,17 @@ impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> } impl<'output, Target> ser::SerializeTupleStruct - for - TupleStructSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, + for TupleStructSerializer<'output, Target> +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_field(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_field( + &mut self, + value: &T, + ) -> Result<(), Error> { self.inner.serialize_field(value) } @@ -390,16 +411,17 @@ impl<'output, Target> ser::SerializeTupleStruct } impl<'output, Target> ser::SerializeTupleVariant - for - TupleVariantSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, + for TupleVariantSerializer<'output, Target> +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_field(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_field( + &mut self, + value: &T, + ) -> Result<(), Error> { self.inner.serialize_field(value) } @@ -409,16 +431,20 @@ impl<'output, Target> ser::SerializeTupleVariant } impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_entry - (&mut self, - key: &K, - value: &V) - -> Result<(), Error> { + fn serialize_entry< + K: ?Sized + ser::Serialize, + V: ?Sized + ser::Serialize, + >( + &mut self, + key: &K, + value: &V, + ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| { let value_sink = value::ValueSink::new(self.urlencoder, &key); value.serialize(part::PartSerializer::new(value_sink))?; @@ -429,18 +455,20 @@ impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> key.serialize(entry_serializer) } - fn serialize_key(&mut self, - key: &T) - -> Result<(), Error> { + fn serialize_key( + &mut self, + key: &T, + ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| Ok(key.into())); let key_serializer = part::PartSerializer::new(key_sink); self.key = Some(key.serialize(key_serializer)?); Ok(()) } - fn serialize_value(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_value( + &mut self, + value: &T, + ) -> Result<(), Error> { { let key = self.key.as_ref().ok_or_else(|| Error::no_key())?; let value_sink = value::ValueSink::new(self.urlencoder, &key); @@ -456,15 +484,17 @@ impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> } impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_field(&mut self, - key: &'static str, - value: &T) - -> Result<(), Error> { + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Error> { let value_sink = value::ValueSink::new(self.urlencoder, key); value.serialize(part::PartSerializer::new(value_sink)) } @@ -475,17 +505,18 @@ impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> } impl<'output, Target> ser::SerializeStructVariant - for - StructVariantSerializer<'output, Target> - where Target: 'output + UrlEncodedTarget, + for StructVariantSerializer<'output, Target> +where + Target: 'output + UrlEncodedTarget, { type Ok = &'output mut UrlEncodedSerializer; type Error = Error; - fn serialize_field(&mut self, - key: &'static str, - value: &T) - -> Result<(), Error> { + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Error> { self.inner.serialize_field(key, value) } diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 8fedcc0a..6df2e3de 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -1,7 +1,7 @@ -use ser::Error; use ser::key::KeySink; use ser::part::PartSerializer; use ser::value::ValueSink; +use ser::Error; use serde::ser; use std::borrow::Cow; use std::mem; @@ -14,7 +14,8 @@ pub struct PairSerializer<'target, Target: 'target + UrlEncodedTarget> { } impl<'target, Target> PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { pub fn new(urlencoder: &'target mut UrlEncodedSerializer) -> Self { PairSerializer { @@ -25,7 +26,8 @@ impl<'target, Target> PairSerializer<'target, Target> } impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; @@ -101,29 +103,30 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> Err(Error::unsupported_pair()) } - fn serialize_unit_variant(self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str) - -> Result<(), Error> { + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_newtype_struct - (self, - _name: &'static str, - value: &T) - -> Result<(), Error> { + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &T, + ) -> Result<(), Error> { value.serialize(self) } - fn serialize_newtype_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T) - -> Result<(), Error> { + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<(), Error> { Err(Error::unsupported_pair()) } @@ -131,15 +134,17 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> Ok(()) } - fn serialize_some(self, - value: &T) - -> Result<(), Error> { + fn serialize_some( + self, + value: &T, + ) -> Result<(), Error> { value.serialize(self) } - fn serialize_seq(self, - _len: Option) - -> Result { + fn serialize_seq( + self, + _len: Option, + ) -> Result { Err(Error::unsupported_pair()) } @@ -151,56 +156,61 @@ impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> } } - fn serialize_tuple_struct(self, - _name: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_tuple_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_map(self, - _len: Option) - -> Result { + fn serialize_map( + self, + _len: Option, + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_struct(self, - _name: &'static str, - _len: usize) - -> Result { + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_struct_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(Error::unsupported_pair()) } } impl<'target, Target> ser::SerializeTuple for PairSerializer<'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; - fn serialize_element(&mut self, - value: &T) - -> Result<(), Error> { + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Error> { match mem::replace(&mut self.state, PairState::Done) { PairState::WaitingForKey => { let key_sink = KeySink::new(|key| Ok(key.into())); diff --git a/src/ser/part.rs b/src/ser/part.rs index 36ce1414..f72846cc 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -17,18 +17,19 @@ impl PartSerializer { pub trait Sink: Sized { type Ok; - fn serialize_static_str(self, - value: &'static str) - -> Result; + fn serialize_static_str( + self, + value: &'static str, + ) -> Result; fn serialize_str(self, value: &str) -> Result; fn serialize_string(self, value: String) -> Result; fn serialize_none(self) -> Result; - fn serialize_some - (self, - value: &T) - -> Result; + fn serialize_some( + self, + value: &T, + ) -> Result; fn unsupported(self) -> Error; } @@ -45,7 +46,8 @@ impl ser::Serializer for PartSerializer { type SerializeStructVariant = ser::Impossible; fn serialize_bool(self, v: bool) -> Result { - self.sink.serialize_static_str(if v { "true" } else { "false" }) + self.sink + .serialize_static_str(if v { "true" } else { "false" }) } fn serialize_i8(self, v: i8) -> Result { @@ -111,29 +113,30 @@ impl ser::Serializer for PartSerializer { self.sink.serialize_static_str(name.into()) } - fn serialize_unit_variant(self, - _name: &'static str, - _variant_index: u32, - variant: &'static str) - -> Result { + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { self.sink.serialize_static_str(variant.into()) } - fn serialize_newtype_struct - (self, - _name: &'static str, - value: &T) - -> Result { + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &T, + ) -> Result { value.serialize(self) } - fn serialize_newtype_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T) - -> Result { + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result { Err(self.sink.unsupported()) } @@ -141,68 +144,75 @@ impl ser::Serializer for PartSerializer { self.sink.serialize_none() } - fn serialize_some(self, - value: &T) - -> Result { + fn serialize_some( + self, + value: &T, + ) -> Result { self.sink.serialize_some(value) } - fn serialize_seq(self, - _len: Option) - -> Result { + fn serialize_seq( + self, + _len: Option, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_tuple(self, - _len: usize) - -> Result { + fn serialize_tuple( + self, + _len: usize, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_tuple_struct(self, - _name: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_tuple_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_map(self, - _len: Option) - -> Result { + fn serialize_map( + self, + _len: Option, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_struct(self, - _name: &'static str, - _len: usize) - -> Result { + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { Err(self.sink.unsupported()) } - fn serialize_struct_variant - (self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize) - -> Result { + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { Err(self.sink.unsupported()) } } impl PartSerializer { fn serialize_integer(self, value: I) -> Result - where I: itoa::Integer, + where + I: itoa::Integer, { let mut buf = [b'\0'; 20]; let len = itoa::write(&mut buf[..], value).unwrap(); @@ -211,7 +221,8 @@ impl PartSerializer { } fn serialize_floating(self, value: F) -> Result - where F: dtoa::Floating, + where + F: dtoa::Floating, { let mut buf = [b'\0'; 24]; let len = dtoa::write(&mut buf[..], value).unwrap(); diff --git a/src/ser/value.rs b/src/ser/value.rs index e4e1f2ce..13204d49 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -1,23 +1,26 @@ -use ser::Error; use ser::part::{PartSerializer, Sink}; +use ser::Error; use serde::ser::Serialize; use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; pub struct ValueSink<'key, 'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { urlencoder: &'target mut UrlEncodedSerializer, key: &'key str, } impl<'key, 'target, Target> ValueSink<'key, 'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { - pub fn new(urlencoder: &'target mut UrlEncodedSerializer, - key: &'key str) - -> Self { + pub fn new( + urlencoder: &'target mut UrlEncodedSerializer, + key: &'key str, + ) -> Self { ValueSink { urlencoder: urlencoder, key: key, @@ -26,7 +29,8 @@ impl<'key, 'target, Target> ValueSink<'key, 'target, Target> } impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> - where Target: 'target + UrlEncodedTarget, +where + Target: 'target + UrlEncodedTarget, { type Ok = (); @@ -47,9 +51,10 @@ impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> Ok(()) } - fn serialize_some(self, - value: &T) - -> Result { + fn serialize_some( + self, + value: &T, + ) -> Result { value.serialize(PartSerializer::new(self)) } diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index a0065066..a9ae9f0a 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -9,32 +9,34 @@ struct NewType(T); fn deserialize_newtype_i32() { let result = vec![("field".to_owned(), NewType(11))]; - assert_eq!(serde_urlencoded::from_str("field=11"), - Ok(result)); + assert_eq!(serde_urlencoded::from_str("field=11"), Ok(result)); } #[test] fn deserialize_bytes() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; - assert_eq!(serde_urlencoded::from_bytes(b"first=23&last=42"), - Ok(result)); + assert_eq!( + serde_urlencoded::from_bytes(b"first=23&last=42"), + Ok(result) + ); } #[test] fn deserialize_str() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; - assert_eq!(serde_urlencoded::from_str("first=23&last=42"), - Ok(result)); + assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_reader() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; - assert_eq!(serde_urlencoded::from_reader(b"first=23&last=42" as &[_]), - Ok(result)); + assert_eq!( + serde_urlencoded::from_reader(b"first=23&last=42" as &[_]), + Ok(result) + ); } #[test] @@ -66,8 +68,11 @@ fn deserialize_unit_enum() { let result = vec![ ("one".to_owned(), X::A), ("two".to_owned(), X::B), - ("three".to_owned(), X::C) + ("three".to_owned(), X::C), ]; - assert_eq!(serde_urlencoded::from_str("one=A&two=B&three=C"), Ok(result)); + assert_eq!( + serde_urlencoded::from_str("one=A&two=B&three=C"), + Ok(result) + ); } diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 5f2b95ef..6f99cba6 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -7,7 +7,7 @@ struct NewType(T); #[test] fn serialize_newtype_i32() { - let params = &[("field", Some(NewType(11))),]; + let params = &[("field", Some(NewType(11)))]; assert_eq!( serde_urlencoded::to_string(params), Ok("field=11".to_owned()) @@ -18,33 +18,44 @@ fn serialize_newtype_i32() { fn serialize_option_map_int() { let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; - assert_eq!(serde_urlencoded::to_string(params), - Ok("first=23&last=42".to_owned())); + assert_eq!( + serde_urlencoded::to_string(params), + Ok("first=23&last=42".to_owned()) + ); } #[test] fn serialize_option_map_string() { - let params = - &[("first", Some("hello")), ("middle", None), ("last", Some("world"))]; + let params = &[ + ("first", Some("hello")), + ("middle", None), + ("last", Some("world")), + ]; - assert_eq!(serde_urlencoded::to_string(params), - Ok("first=hello&last=world".to_owned())); + assert_eq!( + serde_urlencoded::to_string(params), + Ok("first=hello&last=world".to_owned()) + ); } #[test] fn serialize_option_map_bool() { let params = &[("one", Some(true)), ("two", Some(false))]; - assert_eq!(serde_urlencoded::to_string(params), - Ok("one=true&two=false".to_owned())); + assert_eq!( + serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned()) + ); } #[test] fn serialize_map_bool() { let params = &[("one", true), ("two", false)]; - assert_eq!(serde_urlencoded::to_string(params), - Ok("one=true&two=false".to_owned())); + assert_eq!( + serde_urlencoded::to_string(params), + Ok("one=true&two=false".to_owned()) + ); } #[derive(Serialize)] @@ -57,6 +68,8 @@ enum X { #[test] fn serialize_unit_enum() { let params = &[("one", X::A), ("two", X::B), ("three", X::C)]; - assert_eq!(serde_urlencoded::to_string(params), - Ok("one=A&two=B&three=C".to_owned())); + assert_eq!( + serde_urlencoded::to_string(params), + Ok("one=A&two=B&three=C".to_owned()) + ); } From 98f0113592da64dbf8425b845194469ec3d5c0d8 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 16 Apr 2019 11:26:25 +0200 Subject: [PATCH 40/95] Don't use CowStrDeserializer (fixes #53) --- src/de.rs | 5 ++++- tests/test_deserialize.rs | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/de.rs b/src/de.rs index bee94a92..3558f3e2 100644 --- a/src/de.rs +++ b/src/de.rs @@ -194,7 +194,10 @@ impl<'de> de::Deserializer<'de> for Part<'de> { where V: de::Visitor<'de>, { - self.0.into_deserializer().deserialize_any(visitor) + match self.0 { + Cow::Borrowed(value) => visitor.visit_borrowed_str(value), + Cow::Owned(value) => visitor.visit_string(value), + } } fn deserialize_option(self, visitor: V) -> Result diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index a9ae9f0a..69105995 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -29,6 +29,13 @@ fn deserialize_str() { assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); } +#[test] +fn deserialize_borrowed_str() { + let result = vec![("first", 23), ("last", 42)]; + + assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); +} + #[test] fn deserialize_reader() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; From 2bb996055b45f89b0f04793c732f4f55468ba5b3 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 16 Apr 2019 11:27:24 +0200 Subject: [PATCH 41/95] Bump version to 0.5.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a82d29bd..ca63e5c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.4" +version = "0.5.5" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 76b45ee0014723106c23be188f0296920a19965c Mon Sep 17 00:00:00 2001 From: Florian Dehau Date: Sun, 13 Jan 2019 23:17:45 +0100 Subject: [PATCH 42/95] feat: allow serialization of unit structs --- src/ser/mod.rs | 4 ++-- tests/test_serialize.rs | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 633f1faa..18687192 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -227,12 +227,12 @@ where Err(Error::top_level()) } - /// Returns an error. + /// Returns `Ok`. fn serialize_unit_struct( self, _name: &'static str, ) -> Result { - Err(Error::top_level()) + Ok(self.urlencoder) } /// Returns an error. diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 6f99cba6..b0276d2e 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -73,3 +73,11 @@ fn serialize_unit_enum() { Ok("one=A&two=B&three=C".to_owned()) ); } + +#[derive(Serialize)] +struct Unit; + +#[test] +fn serialize_unit_struct() { + assert_eq!(serde_urlencoded::to_string(Unit), Ok("".to_owned())); +} From 99ef71ac2ebb323352c0a61ca3ff932651ab42b1 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 23 Jul 2019 18:34:37 +0200 Subject: [PATCH 43/95] Update the url crate to 2.0 --- Cargo.toml | 4 ++-- src/ser/mod.rs | 34 +++++++++++++++++----------------- src/ser/pair.rs | 4 ++-- src/ser/value.rs | 4 ++-- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ca63e5c0..0ffeac31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.5" +version = "0.5.6" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" @@ -19,7 +19,7 @@ test = false dtoa = "0.4.0" itoa = "0.4.0" serde = "1.0.0" -url = "1.0.0" +url = "2.0.0" [dev-dependencies] serde_derive = "1.0" diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 633f1faa..c95a321c 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -43,12 +43,12 @@ pub fn to_string(input: T) -> Result { /// /// * Newtype structs defer to their inner values. pub struct Serializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, + urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, } impl<'output, Target: 'output + UrlEncodedTarget> Serializer<'output, Target> { /// Returns a new `Serializer`. - pub fn new(urlencoder: &'output mut UrlEncodedSerializer) -> Self { + pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'static, Target>) -> Self { Serializer { urlencoder: urlencoder, } @@ -96,53 +96,53 @@ impl ser::Error for Error { /// Sequence serializer. pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, + urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, } /// Tuple serializer. /// /// Mostly used for arrays. pub struct TupleSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, + urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. pub struct TupleStructSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. pub struct TupleVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, } /// Map serializer. pub struct MapSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, + urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, key: Option>, } /// Struct serializer. pub struct StructSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer, + urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, } /// Struct variant serializer. /// /// Never instantiated, struct variants are not supported. pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer, Error>, + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, } impl<'output, Target> ser::Serializer for Serializer<'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; type SerializeSeq = SeqSerializer<'output, Target>; type SerializeTuple = TupleSerializer<'output, Target>; @@ -356,7 +356,7 @@ impl<'output, Target> ser::SerializeSeq for SeqSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_element( @@ -375,7 +375,7 @@ impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_element( @@ -395,7 +395,7 @@ impl<'output, Target> ser::SerializeTupleStruct where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_field( @@ -415,7 +415,7 @@ impl<'output, Target> ser::SerializeTupleVariant where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_field( @@ -434,7 +434,7 @@ impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_entry< @@ -487,7 +487,7 @@ impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_field( @@ -509,7 +509,7 @@ impl<'output, Target> ser::SerializeStructVariant where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer; + type Ok = &'output mut UrlEncodedSerializer<'static, Target>; type Error = Error; fn serialize_field( diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 6df2e3de..596698ef 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -9,7 +9,7 @@ use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; pub struct PairSerializer<'target, Target: 'target + UrlEncodedTarget> { - urlencoder: &'target mut UrlEncodedSerializer, + urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, state: PairState, } @@ -17,7 +17,7 @@ impl<'target, Target> PairSerializer<'target, Target> where Target: 'target + UrlEncodedTarget, { - pub fn new(urlencoder: &'target mut UrlEncodedSerializer) -> Self { + pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'static, Target>) -> Self { PairSerializer { urlencoder: urlencoder, state: PairState::WaitingForKey, diff --git a/src/ser/value.rs b/src/ser/value.rs index 13204d49..526a65bd 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -9,7 +9,7 @@ pub struct ValueSink<'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { - urlencoder: &'target mut UrlEncodedSerializer, + urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, key: &'key str, } @@ -18,7 +18,7 @@ where Target: 'target + UrlEncodedTarget, { pub fn new( - urlencoder: &'target mut UrlEncodedSerializer, + urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, key: &'key str, ) -> Self { ValueSink { From 59f990aba4527e322d89384d8035b60dacb873bd Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Mon, 29 Jul 2019 10:19:29 +0200 Subject: [PATCH 44/95] url is a public dependency, so updating it to 2.0 is a breaking change --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0ffeac31..63fdc1a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.5.6" +version = "0.6.0" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From 31641affadc099eea85cbef0b028fc2d2975863c Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Tue, 30 Jul 2019 13:26:36 -0400 Subject: [PATCH 45/95] Expose lifetimes in UrlEncodedSerializer Forcing UrlEncodedSerializer to have a 'static lifetime is unnecessarily restrictive and breaks a downstream dependency, reqwest. Thread a new lifetime through to fix the problem. --- src/ser/mod.rs | 88 ++++++++++++++++++++++++------------------------ src/ser/pair.rs | 12 +++---- src/ser/value.rs | 10 +++--- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 39e48981..598b3a4d 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -42,13 +42,13 @@ pub fn to_string(input: T) -> Result { /// unit structs and unit variants. /// /// * Newtype structs defer to their inner values. -pub struct Serializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, +pub struct Serializer<'input, 'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } -impl<'output, Target: 'output + UrlEncodedTarget> Serializer<'output, Target> { +impl<'input, 'output, Target: 'output + UrlEncodedTarget> Serializer<'input, 'output, Target> { /// Returns a new `Serializer`. - pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'static, Target>) -> Self { + pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'input, Target>) -> Self { Serializer { urlencoder: urlencoder, } @@ -95,62 +95,62 @@ impl ser::Error for Error { } /// Sequence serializer. -pub struct SeqSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, +pub struct SeqSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Tuple serializer. /// /// Mostly used for arrays. -pub struct TupleSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, +pub struct TupleSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. -pub struct TupleStructSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, +pub struct TupleStructSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. -pub struct TupleVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, +pub struct TupleVariantSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } /// Map serializer. -pub struct MapSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, +pub struct MapSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, key: Option>, } /// Struct serializer. -pub struct StructSerializer<'output, Target: 'output + UrlEncodedTarget> { - urlencoder: &'output mut UrlEncodedSerializer<'static, Target>, +pub struct StructSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Struct variant serializer. /// /// Never instantiated, struct variants are not supported. -pub struct StructVariantSerializer<'output, T: 'output + UrlEncodedTarget> { - inner: ser::Impossible<&'output mut UrlEncodedSerializer<'static, T>, Error>, +pub struct StructVariantSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { + inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } -impl<'output, Target> ser::Serializer for Serializer<'output, Target> +impl<'input, 'output, Target> ser::Serializer for Serializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; - type SerializeSeq = SeqSerializer<'output, Target>; - type SerializeTuple = TupleSerializer<'output, Target>; - type SerializeTupleStruct = TupleStructSerializer<'output, Target>; - type SerializeTupleVariant = TupleVariantSerializer<'output, Target>; - type SerializeMap = MapSerializer<'output, Target>; - type SerializeStruct = StructSerializer<'output, Target>; - type SerializeStructVariant = StructVariantSerializer<'output, Target>; + type SerializeSeq = SeqSerializer<'input, 'output, Target>; + type SerializeTuple = TupleSerializer<'input, 'output, Target>; + type SerializeTupleStruct = TupleStructSerializer<'input, 'output, Target>; + type SerializeTupleVariant = TupleVariantSerializer<'input, 'output, Target>; + type SerializeMap = MapSerializer<'input, 'output, Target>; + type SerializeStruct = StructSerializer<'input, 'output, Target>; + type SerializeStructVariant = StructVariantSerializer<'input, 'output, Target>; /// Returns an error. fn serialize_bool(self, _v: bool) -> Result { @@ -352,11 +352,11 @@ where } } -impl<'output, Target> ser::SerializeSeq for SeqSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeSeq for SeqSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_element( @@ -371,11 +371,11 @@ where } } -impl<'output, Target> ser::SerializeTuple for TupleSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeTuple for TupleSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_element( @@ -390,12 +390,12 @@ where } } -impl<'output, Target> ser::SerializeTupleStruct - for TupleStructSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeTupleStruct + for TupleStructSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( @@ -410,12 +410,12 @@ where } } -impl<'output, Target> ser::SerializeTupleVariant - for TupleVariantSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeTupleVariant + for TupleVariantSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( @@ -430,11 +430,11 @@ where } } -impl<'output, Target> ser::SerializeMap for MapSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeMap for MapSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_entry< @@ -483,11 +483,11 @@ where } } -impl<'output, Target> ser::SerializeStruct for StructSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeStruct for StructSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( @@ -504,12 +504,12 @@ where } } -impl<'output, Target> ser::SerializeStructVariant - for StructVariantSerializer<'output, Target> +impl<'input, 'output, Target> ser::SerializeStructVariant + for StructVariantSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { - type Ok = &'output mut UrlEncodedSerializer<'static, Target>; + type Ok = &'output mut UrlEncodedSerializer<'input, Target>; type Error = Error; fn serialize_field( diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 596698ef..e7235e43 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -8,16 +8,16 @@ use std::mem; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; -pub struct PairSerializer<'target, Target: 'target + UrlEncodedTarget> { - urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, +pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { + urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, state: PairState, } -impl<'target, Target> PairSerializer<'target, Target> +impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { - pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'static, Target>) -> Self { + pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'input, Target>) -> Self { PairSerializer { urlencoder: urlencoder, state: PairState::WaitingForKey, @@ -25,7 +25,7 @@ where } } -impl<'target, Target> ser::Serializer for PairSerializer<'target, Target> +impl<'input, 'target, Target> ser::Serializer for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { @@ -200,7 +200,7 @@ where } } -impl<'target, Target> ser::SerializeTuple for PairSerializer<'target, Target> +impl<'input, 'target, Target> ser::SerializeTuple for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { diff --git a/src/ser/value.rs b/src/ser/value.rs index 526a65bd..fc12076a 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -5,20 +5,20 @@ use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; -pub struct ValueSink<'key, 'target, Target> +pub struct ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { - urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, + urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, } -impl<'key, 'target, Target> ValueSink<'key, 'target, Target> +impl<'input, 'key, 'target, Target> ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { pub fn new( - urlencoder: &'target mut UrlEncodedSerializer<'static, Target>, + urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, ) -> Self { ValueSink { @@ -28,7 +28,7 @@ where } } -impl<'key, 'target, Target> Sink for ValueSink<'key, 'target, Target> +impl<'input, 'key, 'target, Target> Sink for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { From 278de79267418c3f12bc1827227918ea3c396b6e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 31 Jul 2019 10:49:32 +0200 Subject: [PATCH 46/95] Bump version to 0.6.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 63fdc1a6..383d5683 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_urlencoded" -version = "0.6.0" +version = "0.6.1" authors = ["Anthony Ramine "] license = "MIT/Apache-2.0" repository = "https://github.com/nox/serde_urlencoded" From eb3c5234446d7f545d1e8b868e1fccce45d1cad2 Mon Sep 17 00:00:00 2001 From: Igor Gnatenko Date: Sun, 25 Aug 2019 14:10:44 +0200 Subject: [PATCH 47/95] chore: Exclude unneeded files --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 383d5683..d1f6845c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ documentation = "https://docs.rs/serde_urlencoded" description = "`x-www-form-urlencoded` meets Serde" categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] +exclude = ["/.travis.yml", "/bors.toml"] [badges] travis-ci = {repository = "nox/serde_urlencoded"} From ed2b92f98b2fadb9be0007a3e7ff14b6da98f8b1 Mon Sep 17 00:00:00 2001 From: Andrii Radyk Date: Mon, 20 Jan 2020 23:07:27 +0100 Subject: [PATCH 48/95] add Error::source --- src/ser/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 598b3a4d..51d92af9 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -86,6 +86,14 @@ impl error::Error for Error { Error::Utf8(ref err) => Some(err), } } + + /// The lower-level source of this error, in the case of a `Utf8` error. + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + Error::Custom(_) => None, + Error::Utf8(ref err) => Some(err), + } + } } impl ser::Error for Error { From 12c95203e0d48d13e222b339646097838ca5c0d4 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Tue, 10 Mar 2020 12:38:30 +0900 Subject: [PATCH 49/95] replace typo in documentation --- src/de.rs | 4 ++-- src/ser/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/de.rs b/src/de.rs index 3558f3e2..813bcf7e 100644 --- a/src/de.rs +++ b/src/de.rs @@ -11,7 +11,7 @@ use url::form_urlencoded::Parse as UrlEncodedParse; #[doc(inline)] pub use serde::de::value::Error; -/// Deserializes a `application/x-wwww-url-encoded` value from a `&[u8]`. +/// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`. /// /// ``` /// let meal = vec![ @@ -33,7 +33,7 @@ where T::deserialize(Deserializer::new(parse(input))) } -/// Deserializes a `application/x-wwww-url-encoded` value from a `&str`. +/// Deserializes a `application/x-www-form-urlencoded` value from a `&str`. /// /// ``` /// let meal = vec![ diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 51d92af9..a600552b 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -13,7 +13,7 @@ use std::str; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; -/// Serializes a value into a `application/x-wwww-url-encoded` `String` buffer. +/// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// /// ``` /// let meal = &[ From f60e4fd093fa1fbf8351c24d5e5711de142181a7 Mon Sep 17 00:00:00 2001 From: MaxV <60802079+maxv-rust@users.noreply.github.com> Date: Wed, 8 Apr 2020 23:02:57 -0700 Subject: [PATCH 50/95] Allow serialization of unit type --- src/ser/mod.rs | 4 ++-- tests/test_deserialize.rs | 5 +++++ tests/test_serialize.rs | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ser/mod.rs b/src/ser/mod.rs index a600552b..4e21fb8d 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -230,9 +230,9 @@ where Err(Error::top_level()) } - /// Returns an error. + /// Returns `Ok`. fn serialize_unit(self) -> Result { - Err(Error::top_level()) + Ok(self.urlencoder) } /// Returns `Ok`. diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index 69105995..bb276217 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -83,3 +83,8 @@ fn deserialize_unit_enum() { Ok(result) ); } + +#[test] +fn deserialize_unit_type() { + assert_eq!(serde_urlencoded::from_str(""), Ok(())); +} diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index b0276d2e..60c6ff74 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -81,3 +81,8 @@ struct Unit; fn serialize_unit_struct() { assert_eq!(serde_urlencoded::to_string(Unit), Ok("".to_owned())); } + +#[test] +fn serialize_unit_type() { + assert_eq!(serde_urlencoded::to_string(()), Ok("".to_owned())); +} From c0e751669fb64067b12dde8aec185d368479d939 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 17 Apr 2020 19:47:59 +0200 Subject: [PATCH 51/95] Initial commit (import code from ruma-client-api) Co-authored-by: Isaiah Inuwa --- .gitignore | 9 +++ Cargo.toml | 20 ++++++ src/duration.rs | 4 ++ src/duration/opt_ms.rs | 102 ++++++++++++++++++++++++++++ src/duration/secs.rs | 69 +++++++++++++++++++ src/json_string.rs | 24 +++++++ src/lib.rs | 9 +++ src/time.rs | 4 ++ src/time/ms_since_unix_epoch.rs | 78 +++++++++++++++++++++ src/time/opt_ms_since_unix_epoch.rs | 100 +++++++++++++++++++++++++++ 10 files changed, 419 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/duration.rs create mode 100644 src/duration/opt_ms.rs create mode 100644 src/duration/secs.rs create mode 100644 src/json_string.rs create mode 100644 src/lib.rs create mode 100644 src/time.rs create mode 100644 src/time/ms_since_unix_epoch.rs create mode 100644 src/time/opt_ms_since_unix_epoch.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1e4c8083 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/target + + +#Added by cargo +# +#already existing elements were commented out + +#/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..1a4a25a8 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ruma-serde" +description = "De-/serialization helpers for other ruma crates" +documentation = "https://docs.rs/ruma-serde" +license = "MIT" +authors = [ + "Jonas Platte ", + "Isaiah Inuwa ", +] +version = "0.1.0" +repository = "https://github.com/ruma/ruma-serde" +edition = "2018" + +[dependencies] +js_int = { version = "0.1.4", features = ["serde"] } +serde = "1.0.106" +serde_json = "1.0.51" + +[dev-dependencies] +serde = { version = "1.0.106", features = ["derive"] } diff --git a/src/duration.rs b/src/duration.rs new file mode 100644 index 00000000..d8c895fa --- /dev/null +++ b/src/duration.rs @@ -0,0 +1,4 @@ +//! De-/serialization functions for `std::time::Duration` objects + +pub mod opt_ms; +pub mod secs; diff --git a/src/duration/opt_ms.rs b/src/duration/opt_ms.rs new file mode 100644 index 00000000..1e8d6462 --- /dev/null +++ b/src/duration/opt_ms.rs @@ -0,0 +1,102 @@ +//! De-/serialization functions for `Option` objects represented as milliseconds. +//! Delegates to `js_int::UInt` to ensure integer size is within bounds. + +use std::{convert::TryFrom, time::Duration}; + +use js_int::UInt; +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Error, Serialize, Serializer}, +}; + +/// Serialize an Option. +/// +/// Will fail if integer is greater than the maximum integer that can be +/// unambiguously represented by an f64. +pub fn serialize(opt_duration: &Option, serializer: S) -> Result +where + S: Serializer, +{ + match opt_duration { + Some(duration) => match UInt::try_from(duration.as_millis()) { + Ok(uint) => uint.serialize(serializer), + Err(err) => Err(S::Error::custom(err)), + }, + None => serializer.serialize_none(), + } +} + +/// Deserializes an Option. +/// +/// Will fail if integer is greater than the maximum integer that can be +/// unambiguously represented by an f64. +pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + Ok(Option::::deserialize(deserializer)? + .map(|millis| Duration::from_millis(millis.into()))) +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use serde::{Deserialize, Serialize}; + use serde_json::json; + + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] + struct DurationTest { + #[serde(with = "super", default, skip_serializing_if = "Option::is_none")] + timeout: Option, + } + + #[test] + fn test_deserialize_some() { + let json = json!({ "timeout": 3000 }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + DurationTest { + timeout: Some(Duration::from_millis(3000)) + }, + ); + } + + #[test] + fn test_deserialize_none_by_absence() { + let json = json!({}); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + DurationTest { timeout: None }, + ); + } + + #[test] + fn test_deserialize_none_by_null() { + let json = json!({ "timeout": null }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + DurationTest { timeout: None }, + ); + } + + #[test] + fn test_serialize_some() { + let request = DurationTest { + timeout: Some(Duration::new(2, 0)), + }; + assert_eq!( + serde_json::to_value(&request).unwrap(), + json!({ "timeout": 2000 }) + ); + } + + #[test] + fn test_serialize_none() { + let request = DurationTest { timeout: None }; + assert_eq!(serde_json::to_value(&request).unwrap(), json!({})); + } +} diff --git a/src/duration/secs.rs b/src/duration/secs.rs new file mode 100644 index 00000000..830eb4d5 --- /dev/null +++ b/src/duration/secs.rs @@ -0,0 +1,69 @@ +//! De-/serialization functions for `Option` objects represented as milliseconds. +//! Delegates to `js_int::UInt` to ensure integer size is within bounds. + +use std::{convert::TryFrom, time::Duration}; + +use js_int::UInt; +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Error, Serialize, Serializer}, +}; + +/// Serializes a Duration to an integer representing seconds. +/// +/// Will fail if integer is greater than the maximum integer that can be +/// unambiguously represented by an f64. +pub fn serialize(duration: &Duration, serializer: S) -> Result +where + S: Serializer, +{ + match UInt::try_from(duration.as_secs()) { + Ok(uint) => uint.serialize(serializer), + Err(err) => Err(S::Error::custom(err)), + } +} + +/// Deserializes an integer representing seconds into a Duration. +/// +/// Will fail if integer is greater than the maximum integer that can be +/// unambiguously represented by an f64. +pub fn deserialize<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + UInt::deserialize(deserializer).map(|secs| Duration::from_secs(secs.into())) +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use serde::{Deserialize, Serialize}; + use serde_json::json; + + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] + struct DurationTest { + #[serde(with = "super")] + timeout: Duration, + } + + #[test] + fn test_deserialize() { + let json = json!({ "timeout": 3 }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + DurationTest { + timeout: Duration::from_secs(3) + }, + ); + } + + #[test] + fn test_serialize() { + let test = DurationTest { + timeout: Duration::from_millis(7000), + }; + assert_eq!(serde_json::to_value(test).unwrap(), json!({ "timeout": 7 }),); + } +} diff --git a/src/json_string.rs b/src/json_string.rs new file mode 100644 index 00000000..e5fabe70 --- /dev/null +++ b/src/json_string.rs @@ -0,0 +1,24 @@ +//! De-/serialization functions to and from json strings, allows the type to be used as a query string. + +use serde::{ + de::{Deserialize, DeserializeOwned, Deserializer, Error as _}, + ser::{Error as _, Serialize, Serializer}, +}; + +pub fn serialize(filter: T, serializer: S) -> Result +where + T: Serialize, + S: Serializer, +{ + let json = serde_json::to_string(&filter).map_err(S::Error::custom)?; + serializer.serialize_str(&json) +} + +pub fn deserialize<'de, T, D>(deserializer: D) -> Result +where + T: DeserializeOwned, + D: Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + serde_json::from_str(&s).map_err(D::Error::custom) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..555909aa --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +//! De-/serialization helpers for other ruma crates + +pub mod duration; +pub mod json_string; +pub mod time; + +pub fn is_default(val: &T) -> bool { + val == &T::default() +} diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 00000000..e60bb839 --- /dev/null +++ b/src/time.rs @@ -0,0 +1,4 @@ +//! De-/serialization functions for `std::time::SystemTime` objects + +pub mod ms_since_unix_epoch; +pub mod opt_ms_since_unix_epoch; diff --git a/src/time/ms_since_unix_epoch.rs b/src/time/ms_since_unix_epoch.rs new file mode 100644 index 00000000..ea1b79cc --- /dev/null +++ b/src/time/ms_since_unix_epoch.rs @@ -0,0 +1,78 @@ +//! De-/serialization functions for `std::time::SystemTime` objects represented as milliseconds +//! since the UNIX epoch. Delegates to `js_int::UInt` to ensure integer size is within bounds. + +use std::{ + convert::TryFrom, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use js_int::UInt; +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Error, Serialize, Serializer}, +}; + +/// Serialize a SystemTime. +/// +/// Will fail if integer is greater than the maximum integer that can be unambiguously represented +/// by an f64. +pub fn serialize(time: &SystemTime, serializer: S) -> Result +where + S: Serializer, +{ + // If this unwrap fails, the system this is executed is completely broken. + let time_since_epoch = time.duration_since(UNIX_EPOCH).unwrap(); + match UInt::try_from(time_since_epoch.as_millis()) { + Ok(uint) => uint.serialize(serializer), + Err(err) => Err(S::Error::custom(err)), + } +} + +/// Deserializes a SystemTime. +/// +/// Will fail if integer is greater than the maximum integer that can be unambiguously represented +/// by an f64. +pub fn deserialize<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let millis = UInt::deserialize(deserializer)?; + Ok(UNIX_EPOCH + Duration::from_millis(millis.into())) +} + +#[cfg(test)] +mod tests { + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + + use serde::{Deserialize, Serialize}; + use serde_json::json; + + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] + struct SystemTimeTest { + #[serde(with = "super")] + timestamp: SystemTime, + } + + #[test] + fn test_deserialize() { + let json = json!({ "timestamp": 3000 }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + SystemTimeTest { + timestamp: UNIX_EPOCH + Duration::from_millis(3000), + }, + ); + } + + #[test] + fn test_serialize() { + let request = SystemTimeTest { + timestamp: UNIX_EPOCH + Duration::new(2, 0), + }; + assert_eq!( + serde_json::to_value(&request).unwrap(), + json!({ "timestamp": 2000 }) + ); + } +} diff --git a/src/time/opt_ms_since_unix_epoch.rs b/src/time/opt_ms_since_unix_epoch.rs new file mode 100644 index 00000000..787455ac --- /dev/null +++ b/src/time/opt_ms_since_unix_epoch.rs @@ -0,0 +1,100 @@ +//! De-/serialization functions for `Option` objects represented as +//! milliseconds since the UNIX epoch. Delegates to `js_int::UInt` to ensure integer size is within +//! bounds. + +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use js_int::UInt; +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Serialize, Serializer}, +}; + +/// Serialize an `Option`. +/// +/// Will fail if integer is greater than the maximum integer that can be unambiguously represented +/// by an f64. +pub fn serialize(opt_time: &Option, serializer: S) -> Result +where + S: Serializer, +{ + match opt_time { + Some(time) => super::ms_since_unix_epoch::serialize(time, serializer), + None => Option::::serialize(&None, serializer), + } +} + +/// Deserializes an `Option`. +/// +/// Will fail if integer is greater than the maximum integer that can be unambiguously represented +/// by an f64. +pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + Ok(Option::::deserialize(deserializer)? + .map(|millis| UNIX_EPOCH + Duration::from_millis(millis.into()))) +} + +#[cfg(test)] +mod tests { + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + + use serde::{Deserialize, Serialize}; + use serde_json::json; + + #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] + struct SystemTimeTest { + #[serde(with = "super", default, skip_serializing_if = "Option::is_none")] + timestamp: Option, + } + + #[test] + fn test_deserialize_some() { + let json = json!({ "timestamp": 3000 }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + SystemTimeTest { + timestamp: Some(UNIX_EPOCH + Duration::from_millis(3000)) + }, + ); + } + + #[test] + fn test_deserialize_none_by_absence() { + let json = json!({}); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + SystemTimeTest { timestamp: None }, + ); + } + + #[test] + fn test_deserialize_none_by_null() { + let json = json!({ "timestamp": null }); + + assert_eq!( + serde_json::from_value::(json).unwrap(), + SystemTimeTest { timestamp: None }, + ); + } + + #[test] + fn test_serialize_some() { + let request = SystemTimeTest { + timestamp: Some(UNIX_EPOCH + Duration::new(2, 0)), + }; + assert_eq!( + serde_json::to_value(&request).unwrap(), + json!({ "timestamp": 2000 }) + ); + } + + #[test] + fn test_serialize_none() { + let request = SystemTimeTest { timestamp: None }; + assert_eq!(serde_json::to_value(&request).unwrap(), json!({})); + } +} From 3e4cd7abd4fa3f87c7de3952a10c65928d93979d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 17 Apr 2020 19:54:23 +0200 Subject: [PATCH 52/95] Add LICENSE file, travis configuration --- .travis.yml | 37 +++++++++++++++++++++++++++++++++++++ LICENSE | 19 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 .travis.yml create mode 100644 LICENSE diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..129d203c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,37 @@ +language: "rust" +cache: "cargo" +rust: + - 1.36.0 + - stable + - beta + - nightly +jobs: + allow_failures: + - rust: nightly + fast_finish: true + +before_script: + - rustup component add rustfmt + - | + if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then + rustup component add clippy + fi + - | + if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then + cargo install --force cargo-audit + fi + - cargo generate-lockfile +script: + - | + if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then + cargo audit + fi + - cargo fmt -- --check + - | + if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then + cargo clippy --all-targets --all-features -- -D warnings + fi + - cargo build --verbose + - cargo test --no-default-features --verbose + - cargo test --all-features --verbose +if: "type != push OR (tag IS blank AND branch = master)" diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..4d376442 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016 Jimmy Cuadra + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 68daaf86f654544e01adf27d561505c62cc90688 Mon Sep 17 00:00:00 2001 From: Devin R Date: Mon, 20 Apr 2020 09:11:41 -0400 Subject: [PATCH 53/95] update to 2018 edition, import in ruma style --- Cargo.toml | 12 +++++------- src/de.rs | 14 +++++--------- src/lib.rs | 8 -------- src/ser/key.rs | 9 ++++----- src/ser/mod.rs | 9 +++------ src/ser/pair.rs | 5 +---- src/ser/part.rs | 9 +++++---- src/ser/seq.rs | 0 src/ser/value.rs | 10 +++++----- tests/test_deserialize.rs | 4 +--- tests/test_serialize.rs | 15 ++++++++++++--- 11 files changed, 41 insertions(+), 54 deletions(-) create mode 100644 src/ser/seq.rs diff --git a/Cargo.toml b/Cargo.toml index d1f6845c..e7ff528c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ description = "`x-www-form-urlencoded` meets Serde" categories = ["encoding", "web-programming"] keywords = ["serde", "serialization", "urlencoded"] exclude = ["/.travis.yml", "/bors.toml"] +edition = "2018" [badges] travis-ci = {repository = "nox/serde_urlencoded"} @@ -17,10 +18,7 @@ travis-ci = {repository = "nox/serde_urlencoded"} test = false [dependencies] -dtoa = "0.4.0" -itoa = "0.4.0" -serde = "1.0.0" -url = "2.0.0" - -[dev-dependencies] -serde_derive = "1.0" +dtoa = "0.4.5" +itoa = "0.4.5" +serde = { version = "1.0.106", features = ["derive"] } +url = "2.1.1" diff --git a/src/de.rs b/src/de.rs index 813bcf7e..fe2e0086 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,12 +1,8 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. +use std::{borrow::Cow, io::Read}; -use serde::de::value::MapDeserializer; -use serde::de::Error as de_Error; -use serde::de::{self, IntoDeserializer}; -use std::borrow::Cow; -use std::io::Read; -use url::form_urlencoded::parse; -use url::form_urlencoded::Parse as UrlEncodedParse; +use serde::de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer}; +use url::form_urlencoded::{parse, Parse as UrlEncodedParse}; #[doc(inline)] pub use serde::de::value::Error; @@ -123,7 +119,7 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { visitor.visit_unit() } - forward_to_deserialize_any! { + serde::forward_to_deserialize_any! { bool u8 u16 @@ -230,7 +226,7 @@ impl<'de> de::Deserializer<'de> for Part<'de> { visitor.visit_newtype_struct(self) } - forward_to_deserialize_any! { + serde::forward_to_deserialize_any! { char str string diff --git a/src/lib.rs b/src/lib.rs index 776ae54a..9eb39786 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,5 @@ //! `x-www-form-urlencoded` meets Serde -#![warn(unused_extern_crates)] - -extern crate dtoa; -extern crate itoa; -#[macro_use] -extern crate serde; -extern crate url; - pub mod de; pub mod ser; diff --git a/src/ser/key.rs b/src/ser/key.rs index 2a2e63ac..5a5e1fc7 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -1,9 +1,8 @@ -use ser::part::Sink; -use ser::Error; -use serde::Serialize; -use std::borrow::Cow; -use std::ops::Deref; +use std::{borrow::Cow, ops::Deref}; +use serde::Serialize; + +use crate::ser::{part::Sink, Error}; pub enum Key<'key> { Static(&'static str), Dynamic(Cow<'key, str>), diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 4e21fb8d..1a816d5a 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -5,13 +5,10 @@ mod pair; mod part; mod value; +use std::{borrow::Cow, error, fmt, str}; + use serde::ser; -use std::borrow::Cow; -use std::error; -use std::fmt; -use std::str; -use url::form_urlencoded::Serializer as UrlEncodedSerializer; -use url::form_urlencoded::Target as UrlEncodedTarget; +use url::form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// diff --git a/src/ser/pair.rs b/src/ser/pair.rs index e7235e43..95c06e90 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -1,13 +1,10 @@ -use ser::key::KeySink; -use ser::part::PartSerializer; -use ser::value::ValueSink; -use ser::Error; use serde::ser; use std::borrow::Cow; use std::mem; use url::form_urlencoded::Serializer as UrlEncodedSerializer; use url::form_urlencoded::Target as UrlEncodedTarget; +use crate::ser::{Error, part::PartSerializer, key::KeySink, value::ValueSink}; pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, state: PairState, diff --git a/src/ser/part.rs b/src/ser/part.rs index f72846cc..5e0d64c9 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -1,9 +1,10 @@ -use dtoa; -use itoa; -use ser::Error; -use serde::ser; use std::str; +use dtoa; +use itoa; +use serde::ser; + +use crate::ser::Error; pub struct PartSerializer { sink: S, } diff --git a/src/ser/seq.rs b/src/ser/seq.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/ser/value.rs b/src/ser/value.rs index fc12076a..1ac02df2 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -1,9 +1,9 @@ -use ser::part::{PartSerializer, Sink}; -use ser::Error; -use serde::ser::Serialize; use std::str; -use url::form_urlencoded::Serializer as UrlEncodedSerializer; -use url::form_urlencoded::Target as UrlEncodedTarget; + +use serde::Serialize; +use url::form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; + +use crate::ser::{part::{PartSerializer, Sink}, Error}; pub struct ValueSink<'input, 'key, 'target, Target> where diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index bb276217..c40a03cc 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -1,6 +1,4 @@ -extern crate serde_urlencoded; -#[macro_use] -extern crate serde_derive; +use serde::Deserialize; #[derive(Deserialize, Debug, PartialEq)] struct NewType(T); diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 60c6ff74..630b6d9f 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -1,10 +1,19 @@ -extern crate serde_urlencoded; -#[macro_use] -extern crate serde_derive; +use serde::Serialize; #[derive(Serialize)] struct NewType(T); +#[derive(Serialize)] +struct NewStruct { + list: Vec, +} + +#[test] +fn serialize_newstruct() { + let s = NewStruct { list: vec![ "hello".into() ] }; + println!("{:?}", serde_urlencoded::to_string(s)); +} + #[test] fn serialize_newtype_i32() { let params = &[("field", Some(NewType(11)))]; From 93a7283991aa9c9b1087803c274953d3072c3dc0 Mon Sep 17 00:00:00 2001 From: Devin R Date: Mon, 20 Apr 2020 17:22:08 -0400 Subject: [PATCH 54/95] Add support for matrix-style multiple query parameters This adds support for query strings in which a sequence field of a `Deserialize` / `Serialize` struct is (de)serialized as `field=val1&field=val2&field=val3`, instead of the more common `field[]=val1&field[]=val2&field[]=val3` syntax. --- src/de.rs | 72 ++++++++--- src/error.rs | 69 +++++++++++ src/lib.rs | 1 + src/ser/key.rs | 1 + src/ser/mod.rs | 243 +++++++++++++++++--------------------- src/ser/pair.rs | 213 +++++++++++++++++---------------- src/ser/part.rs | 2 +- src/ser/seq.rs | 0 src/ser/value.rs | 17 +-- tests/test_deserialize.rs | 111 +++++++++++++++++ tests/test_serialize.rs | 119 +++++++++++++++++-- 11 files changed, 577 insertions(+), 271 deletions(-) create mode 100644 src/error.rs delete mode 100644 src/ser/seq.rs diff --git a/src/de.rs b/src/de.rs index fe2e0086..7861f5d4 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1,7 +1,12 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. + use std::{borrow::Cow, io::Read}; -use serde::de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer}; +use serde::de::{ + self, + value::{MapDeserializer, SeqDeserializer}, + Error as de_Error, IntoDeserializer, +}; use url::form_urlencoded::{parse, Parse as UrlEncodedParse}; #[doc(inline)] @@ -65,9 +70,9 @@ where from_bytes(&buf) } -/// A deserializer for the `application/x-www-form-urlencoded` format. +/// A deserializer for the Matrix query string format. /// -/// * Supported top-level outputs are structs, maps and sequences of pairs, +/// * Supported top-level outputs are structs, maps and sequences, /// with or without a given length. /// /// * Main `deserialize` methods defers to `deserialize_map`. @@ -75,15 +80,12 @@ where /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'de> { - inner: MapDeserializer<'de, PartIterator<'de>, Error>, + parser: UrlEncodedParse<'de>, } impl<'de> Deserializer<'de> { - /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'de>) -> Self { - Deserializer { - inner: MapDeserializer::new(PartIterator(parser)), - } + Self { parser } } } @@ -101,21 +103,53 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { where V: de::Visitor<'de>, { - visitor.visit_map(self.inner) + visitor.visit_map(MapDeserializer::new(PartIterator(self.parser))) } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { - visitor.visit_seq(self.inner) + visitor.visit_seq(MapDeserializer::new(PartIterator(self.parser))) + } + + fn deserialize_struct( + self, + _name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let pairs = self.parser.collect::>(); + let mut map = std::collections::VecDeque::new(); + for field in fields { + let values = pairs + .iter() + .filter(|(f, _)| f == field) + .map(|(_f, v)| v.clone()) + .collect::>(); + map.push_back((*field, values)); + } + let parts = fields + .into_iter() + .map(|f| Part(Cow::Borrowed(f), None)) + .zip(PartIterator(self.parser).into_iter().map(|(_, mut v)| { + if let Some((_, val)) = map.pop_front() { + v.1 = Some(val); + } + v + })) + .map(|(field, value)| (field, value)); + visitor.visit_map(MapDeserializer::new(parts)) } fn deserialize_unit(self, visitor: V) -> Result where V: de::Visitor<'de>, { - self.inner.end()?; + MapDeserializer::new(PartIterator(self.parser)).end()?; visitor.visit_unit() } @@ -140,7 +174,6 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { unit_struct newtype_struct tuple_struct - struct identifier tuple enum @@ -154,11 +187,11 @@ impl<'de> Iterator for PartIterator<'de> { type Item = (Part<'de>, Part<'de>); fn next(&mut self) -> Option { - self.0.next().map(|(k, v)| (Part(k), Part(v))) + self.0.next().map(|(k, v)| (Part(k, None), Part(v, None))) } } -struct Part<'de>(Cow<'de, str>); +struct Part<'de>(Cow<'de, str>, Option>>); impl<'de> IntoDeserializer<'de> for Part<'de> { type Deserializer = Self; @@ -226,6 +259,16 @@ impl<'de> de::Deserializer<'de> for Part<'de> { visitor.visit_newtype_struct(self) } + fn deserialize_seq(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + let iter = self.1.ok_or(Error::custom("expected sequence"))?; + visitor.visit_seq(SeqDeserializer::new( + iter.into_iter().map(|v| Part(v, None)), + )) + } + serde::forward_to_deserialize_any! { char str @@ -239,7 +282,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { identifier tuple ignored_any - seq map } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..32a387cd --- /dev/null +++ b/src/error.rs @@ -0,0 +1,69 @@ +use std::{borrow::Cow, error, fmt, str}; + +use serde::ser; + +pub type Result = std::result::Result; + +/// Errors returned during serializing to `application/x-www-form-urlencoded`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Error { + Custom(Cow<'static, str>), + Utf8(str::Utf8Error), +} + +impl Error { + pub fn done() -> Self { + Error::Custom("this pair has already been serialized".into()) + } + + pub fn not_done() -> Self { + Error::Custom("this pair has not yet been serialized".into()) + } + + pub fn unsupported_pair() -> Self { + Error::Custom("unsupported pair".into()) + } + + pub fn top_level() -> Self { + let msg = "top-level serializer supports only maps and structs"; + Error::Custom(msg.into()) + } + + pub fn no_key() -> Self { + let msg = "tried to serialize a value before serializing key"; + Error::Custom(msg.into()) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Custom(ref msg) => msg.fmt(f), + Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), + } + } +} + +impl error::Error for Error { + /// The lower-level cause of this error, in the case of a `Utf8` error. + fn cause(&self) -> Option<&dyn error::Error> { + match *self { + Error::Custom(_) => None, + Error::Utf8(ref err) => Some(err), + } + } + + /// The lower-level source of this error, in the case of a `Utf8` error. + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + Error::Custom(_) => None, + Error::Utf8(ref err) => Some(err), + } + } +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error::Custom(format!("{}", msg).into()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 9eb39786..ee9ef0c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! `x-www-form-urlencoded` meets Serde pub mod de; +pub mod error; pub mod ser; #[doc(inline)] diff --git a/src/ser/key.rs b/src/ser/key.rs index 5a5e1fc7..1906d4b4 100644 --- a/src/ser/key.rs +++ b/src/ser/key.rs @@ -3,6 +3,7 @@ use std::{borrow::Cow, ops::Deref}; use serde::Serialize; use crate::ser::{part::Sink, Error}; + pub enum Key<'key> { Static(&'static str), Dynamic(Cow<'key, str>), diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 1a816d5a..5f4d820f 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -5,10 +5,14 @@ mod pair; mod part; mod value; -use std::{borrow::Cow, error, fmt, str}; +use std::{borrow::Cow, str}; use serde::ser; -use url::form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; +use url::form_urlencoded::{ + Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, +}; + +use crate::error::{Error, Result}; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// @@ -24,7 +28,7 @@ use url::form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEnco /// serde_urlencoded::to_string(meal), /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); /// ``` -pub fn to_string(input: T) -> Result { +pub fn to_string(input: T) -> Result { let mut urlencoder = UrlEncodedSerializer::new("".to_owned()); input.serialize(Serializer::new(&mut urlencoder))?; Ok(urlencoder.finish()) @@ -43,85 +47,50 @@ pub struct Serializer<'input, 'output, Target: 'output + UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } -impl<'input, 'output, Target: 'output + UrlEncodedTarget> Serializer<'input, 'output, Target> { +impl<'input, 'output, Target: 'output + UrlEncodedTarget> + Serializer<'input, 'output, Target> +{ /// Returns a new `Serializer`. - pub fn new(urlencoder: &'output mut UrlEncodedSerializer<'input, Target>) -> Self { + pub fn new( + urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, + ) -> Self { Serializer { urlencoder: urlencoder, } } } -/// Errors returned during serializing to `application/x-www-form-urlencoded`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Error { - Custom(Cow<'static, str>), - Utf8(str::Utf8Error), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Custom(ref msg) => msg.fmt(f), - Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), - } - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Custom(ref msg) => msg, - Error::Utf8(ref err) => error::Error::description(err), - } - } - - /// The lower-level cause of this error, in the case of a `Utf8` error. - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Custom(_) => None, - Error::Utf8(ref err) => Some(err), - } - } - - /// The lower-level source of this error, in the case of a `Utf8` error. - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - Error::Custom(_) => None, - Error::Utf8(ref err) => Some(err), - } - } -} - -impl ser::Error for Error { - fn custom(msg: T) -> Self { - Error::Custom(format!("{}", msg).into()) - } -} - /// Sequence serializer. pub struct SeqSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, + key: Option>, + count: usize, } /// Tuple serializer. /// /// Mostly used for arrays. -pub struct TupleSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { +pub struct TupleSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> +{ urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Tuple struct serializer. /// /// Never instantiated, tuple structs are not supported. -pub struct TupleStructSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { +pub struct TupleStructSerializer<'input, 'output, T: 'output + UrlEncodedTarget> +{ inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } /// Tuple variant serializer. /// /// Never instantiated, tuple variants are not supported. -pub struct TupleVariantSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { +pub struct TupleVariantSerializer< + 'input, + 'output, + T: 'output + UrlEncodedTarget, +> { inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } @@ -132,18 +101,24 @@ pub struct MapSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { } /// Struct serializer. -pub struct StructSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { +pub struct StructSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> +{ urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, } /// Struct variant serializer. /// /// Never instantiated, struct variants are not supported. -pub struct StructVariantSerializer<'input, 'output, T: 'output + UrlEncodedTarget> { +pub struct StructVariantSerializer< + 'input, + 'output, + T: 'output + UrlEncodedTarget, +> { inner: ser::Impossible<&'output mut UrlEncodedSerializer<'input, T>, Error>, } -impl<'input, 'output, Target> ser::Serializer for Serializer<'input, 'output, Target> +impl<'input, 'output, Target> ser::Serializer + for Serializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { @@ -152,91 +127,90 @@ where type SerializeSeq = SeqSerializer<'input, 'output, Target>; type SerializeTuple = TupleSerializer<'input, 'output, Target>; type SerializeTupleStruct = TupleStructSerializer<'input, 'output, Target>; - type SerializeTupleVariant = TupleVariantSerializer<'input, 'output, Target>; + type SerializeTupleVariant = + TupleVariantSerializer<'input, 'output, Target>; type SerializeMap = MapSerializer<'input, 'output, Target>; type SerializeStruct = StructSerializer<'input, 'output, Target>; - type SerializeStructVariant = StructVariantSerializer<'input, 'output, Target>; + type SerializeStructVariant = + StructVariantSerializer<'input, 'output, Target>; /// Returns an error. - fn serialize_bool(self, _v: bool) -> Result { + fn serialize_bool(self, _v: bool) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i8(self, _v: i8) -> Result { + fn serialize_i8(self, _v: i8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i16(self, _v: i16) -> Result { + fn serialize_i16(self, _v: i16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i32(self, _v: i32) -> Result { + fn serialize_i32(self, _v: i32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i64(self, _v: i64) -> Result { + fn serialize_i64(self, _v: i64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u8(self, _v: u8) -> Result { + fn serialize_u8(self, _v: u8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u16(self, _v: u16) -> Result { + fn serialize_u16(self, _v: u16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u32(self, _v: u32) -> Result { + fn serialize_u32(self, _v: u32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u64(self, _v: u64) -> Result { + fn serialize_u64(self, _v: u64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f32(self, _v: f32) -> Result { + fn serialize_f32(self, _v: f32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f64(self, _v: f64) -> Result { + fn serialize_f64(self, _v: f64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_char(self, _v: char) -> Result { + fn serialize_char(self, _v: char) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_str(self, _value: &str) -> Result { + fn serialize_str(self, _value: &str) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_bytes(self, _value: &[u8]) -> Result { + fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::top_level()) } /// Returns `Ok`. - fn serialize_unit(self) -> Result { + fn serialize_unit(self) -> Result { Ok(self.urlencoder) } /// Returns `Ok`. - fn serialize_unit_struct( - self, - _name: &'static str, - ) -> Result { + fn serialize_unit_struct(self, _name: &'static str) -> Result { Ok(self.urlencoder) } @@ -246,7 +220,7 @@ where _name: &'static str, _variant_index: u32, _variant: &'static str, - ) -> Result { + ) -> Result { Err(Error::top_level()) } @@ -255,7 +229,7 @@ where self, _name: &'static str, value: &T, - ) -> Result { + ) -> Result { value.serialize(self) } @@ -266,12 +240,12 @@ where _variant_index: u32, _variant: &'static str, _value: &T, - ) -> Result { + ) -> Result { Err(Error::top_level()) } /// Returns `Ok`. - fn serialize_none(self) -> Result { + fn serialize_none(self) -> Result { Ok(self.urlencoder) } @@ -279,25 +253,21 @@ where fn serialize_some( self, value: &T, - ) -> Result { + ) -> Result { value.serialize(self) } /// Serialize a sequence, given length (if any) is ignored. - fn serialize_seq( - self, - _len: Option, - ) -> Result { + fn serialize_seq(self, _len: Option) -> Result { Ok(SeqSerializer { urlencoder: self.urlencoder, + key: None, + count: 0, }) } /// Returns an error. - fn serialize_tuple( - self, - _len: usize, - ) -> Result { + fn serialize_tuple(self, _len: usize) -> Result { Ok(TupleSerializer { urlencoder: self.urlencoder, }) @@ -308,7 +278,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } @@ -319,15 +289,12 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } /// Serializes a map, given length is ignored. - fn serialize_map( - self, - _len: Option, - ) -> Result { + fn serialize_map(self, _len: Option) -> Result { Ok(MapSerializer { urlencoder: self.urlencoder, key: None, @@ -339,7 +306,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Ok(StructSerializer { urlencoder: self.urlencoder, }) @@ -352,12 +319,13 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } } -impl<'input, 'output, Target> ser::SerializeSeq for SeqSerializer<'input, 'output, Target> +impl<'input, 'output, Target> ser::SerializeSeq + for SeqSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { @@ -367,16 +335,21 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<(), Error> { - value.serialize(pair::PairSerializer::new(self.urlencoder)) + ) -> Result<()> { + value.serialize(pair::PairSerializer::new( + self.urlencoder, + self.key.as_ref(), + &mut self.count, + )) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } -impl<'input, 'output, Target> ser::SerializeTuple for TupleSerializer<'input, 'output, Target> +impl<'input, 'output, Target> ser::SerializeTuple + for TupleSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { @@ -386,11 +359,15 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<(), Error> { - value.serialize(pair::PairSerializer::new(self.urlencoder)) + ) -> Result<()> { + value.serialize(pair::PairSerializer::new( + self.urlencoder, + None, + &mut 0, + )) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -406,11 +383,11 @@ where fn serialize_field( &mut self, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { self.inner.serialize_field(value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } @@ -426,16 +403,17 @@ where fn serialize_field( &mut self, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { self.inner.serialize_field(value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } -impl<'input, 'output, Target> ser::SerializeMap for MapSerializer<'input, 'output, Target> +impl<'input, 'output, Target> ser::SerializeMap + for MapSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { @@ -449,7 +427,7 @@ where &mut self, key: &K, value: &V, - ) -> Result<(), Error> { + ) -> Result<()> { let key_sink = key::KeySink::new(|key| { let value_sink = value::ValueSink::new(self.urlencoder, &key); value.serialize(part::PartSerializer::new(value_sink))?; @@ -463,7 +441,7 @@ where fn serialize_key( &mut self, key: &T, - ) -> Result<(), Error> { + ) -> Result<()> { let key_sink = key::KeySink::new(|key| Ok(key.into())); let key_serializer = part::PartSerializer::new(key_sink); self.key = Some(key.serialize(key_serializer)?); @@ -473,7 +451,7 @@ where fn serialize_value( &mut self, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { { let key = self.key.as_ref().ok_or_else(|| Error::no_key())?; let value_sink = value::ValueSink::new(self.urlencoder, &key); @@ -483,12 +461,13 @@ where Ok(()) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } -impl<'input, 'output, Target> ser::SerializeStruct for StructSerializer<'input, 'output, Target> +impl<'input, 'output, Target> ser::SerializeStruct + for StructSerializer<'input, 'output, Target> where Target: 'output + UrlEncodedTarget, { @@ -499,12 +478,16 @@ where &mut self, key: &'static str, value: &T, - ) -> Result<(), Error> { - let value_sink = value::ValueSink::new(self.urlencoder, key); - value.serialize(part::PartSerializer::new(value_sink)) + ) -> Result<()> { + let key = Cow::Borrowed(key); + let mut count = 0; + let value_sink = + pair::PairSerializer::new(self.urlencoder, Some(&key), &mut count); + value.serialize(value_sink)?; + Ok(()) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -521,23 +504,11 @@ where &mut self, key: &'static str, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { self.inner.serialize_field(key, value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } - -impl Error { - fn top_level() -> Self { - let msg = "top-level serializer supports only maps and structs"; - Error::Custom(msg.into()) - } - - fn no_key() -> Self { - let msg = "tried to serialize a value before serializing key"; - Error::Custom(msg.into()) - } -} diff --git a/src/ser/pair.rs b/src/ser/pair.rs index 95c06e90..82ba3481 100644 --- a/src/ser/pair.rs +++ b/src/ser/pair.rs @@ -1,34 +1,67 @@ -use serde::ser; use std::borrow::Cow; use std::mem; -use url::form_urlencoded::Serializer as UrlEncodedSerializer; -use url::form_urlencoded::Target as UrlEncodedTarget; -use crate::ser::{Error, part::PartSerializer, key::KeySink, value::ValueSink}; +use serde::ser; + +use url::form_urlencoded::{ + Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, +}; + +use crate::{ + error::{Error, Result}, + ser::{key::KeySink, part::PartSerializer, value::ValueSink}, +}; + +macro_rules! serialize_pair { + ($($ty:ty => $name:ident,)*) => { + $( + fn $name(self, value: $ty) -> Result<()> { + let key = if let Some(key) = self.key { + key.clone() + } else { + return Err(Error::no_key()); + }; + let value_sink = ValueSink::new(self.urlencoder, &key); + let value_serializer = PartSerializer::new(value_sink); + value_serializer.$name(value) + } + )* + }; +} + pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, state: PairState, + key: Option<&'target Cow<'target, str>>, + count: &'target mut usize, } impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { - pub fn new(urlencoder: &'target mut UrlEncodedSerializer<'input, Target>) -> Self { + pub fn new( + urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, + key: Option<&'target Cow<'target, str>>, + count: &'target mut usize, + ) -> Self { PairSerializer { - urlencoder: urlencoder, + urlencoder, state: PairState::WaitingForKey, + key, + count, } } } -impl<'input, 'target, Target> ser::Serializer for PairSerializer<'input, 'target, Target> +impl<'input, 'target, Target> ser::Serializer + for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { type Ok = (); type Error = Error; - type SerializeSeq = ser::Impossible<(), Error>; + type SerializeSeq = Self; type SerializeTuple = Self; type SerializeTupleStruct = ser::Impossible<(), Error>; type SerializeTupleVariant = ser::Impossible<(), Error>; @@ -36,67 +69,31 @@ where type SerializeStruct = ser::Impossible<(), Error>; type SerializeStructVariant = ser::Impossible<(), Error>; - fn serialize_bool(self, _v: bool) -> Result<(), Error> { + serialize_pair! { + bool => serialize_bool, + u8 => serialize_u8, + u16 => serialize_u16, + u32 => serialize_u32, + u64 => serialize_u64, + i8 => serialize_i8, + i16 => serialize_i16, + i32 => serialize_i32, + i64 => serialize_i64, + f32 => serialize_f32, + f64 => serialize_f64, + char => serialize_char, + &str => serialize_str, + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<()> { Err(Error::unsupported_pair()) } - fn serialize_i8(self, _v: i8) -> Result<(), Error> { + fn serialize_unit(self) -> Result<()> { Err(Error::unsupported_pair()) } - fn serialize_i16(self, _v: i16) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_i32(self, _v: i32) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_i64(self, _v: i64) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_u8(self, _v: u8) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_u16(self, _v: u16) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_u32(self, _v: u32) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_u64(self, _v: u64) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_f32(self, _v: f32) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_f64(self, _v: f64) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_char(self, _v: char) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_str(self, _value: &str) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_unit(self) -> Result<(), Error> { - Err(Error::unsupported_pair()) - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> { + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { Err(Error::unsupported_pair()) } @@ -104,16 +101,25 @@ where self, _name: &'static str, _variant_index: u32, - _variant: &'static str, - ) -> Result<(), Error> { - Err(Error::unsupported_pair()) + variant: &'static str, + ) -> Result<()> { + let key = if let Some(key) = self.key { + key.clone() + } else { + let key = Cow::Owned(self.count.to_string()); + *self.count += 1; + key + }; + let value_sink = ValueSink::new(self.urlencoder, &key); + let value_serializer = PartSerializer::new(value_sink); + value_serializer.serialize_str(variant) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { value.serialize(self) } @@ -123,29 +129,26 @@ where _variant_index: u32, _variant: &'static str, _value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { Err(Error::unsupported_pair()) } - fn serialize_none(self) -> Result<(), Error> { + fn serialize_none(self) -> Result<()> { Ok(()) } fn serialize_some( self, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { value.serialize(self) } - fn serialize_seq( - self, - _len: Option, - ) -> Result { - Err(Error::unsupported_pair()) + fn serialize_seq(self, _len: Option) -> Result { + Ok(self) } - fn serialize_tuple(self, len: usize) -> Result { + fn serialize_tuple(self, len: usize) -> Result { if len == 2 { Ok(self) } else { @@ -157,7 +160,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } @@ -167,14 +170,11 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_map( - self, - _len: Option, - ) -> Result { + fn serialize_map(self, _len: Option) -> Result { Err(Error::unsupported_pair()) } @@ -182,7 +182,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } @@ -192,12 +192,13 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } } -impl<'input, 'target, Target> ser::SerializeTuple for PairSerializer<'input, 'target, Target> +impl<'input, 'target, Target> ser::SerializeSeq + for PairSerializer<'input, 'target, Target> where Target: 'target + UrlEncodedTarget, { @@ -207,7 +208,31 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<(), Error> { + ) -> Result<()> { + value.serialize(PairSerializer::new( + self.urlencoder, + self.key, + &mut self.count, + )) + } + + fn end(self) -> Result { + Ok(()) + } +} + +impl<'input, 'target, Target> ser::SerializeTuple + for PairSerializer<'input, 'target, Target> +where + Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_element( + &mut self, + value: &T, + ) -> Result<()> { match mem::replace(&mut self.state, PairState::Done) { PairState::WaitingForKey => { let key_sink = KeySink::new(|key| Ok(key.into())); @@ -234,7 +259,7 @@ where } } - fn end(self) -> Result<(), Error> { + fn end(self) -> Result<()> { if let PairState::Done = self.state { Ok(()) } else { @@ -248,17 +273,3 @@ enum PairState { WaitingForValue { key: Cow<'static, str> }, Done, } - -impl Error { - fn done() -> Self { - Error::Custom("this pair has already been serialized".into()) - } - - fn not_done() -> Self { - Error::Custom("this pair has not yet been serialized".into()) - } - - fn unsupported_pair() -> Self { - Error::Custom("unsupported pair".into()) - } -} diff --git a/src/ser/part.rs b/src/ser/part.rs index 5e0d64c9..514d4a27 100644 --- a/src/ser/part.rs +++ b/src/ser/part.rs @@ -4,7 +4,7 @@ use dtoa; use itoa; use serde::ser; -use crate::ser::Error; +use crate::error::Error; pub struct PartSerializer { sink: S, } diff --git a/src/ser/seq.rs b/src/ser/seq.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/ser/value.rs b/src/ser/value.rs index 1ac02df2..a34238ad 100644 --- a/src/ser/value.rs +++ b/src/ser/value.rs @@ -1,9 +1,14 @@ use std::str; use serde::Serialize; -use url::form_urlencoded::{Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget}; +use url::form_urlencoded::{ + Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, +}; -use crate::ser::{part::{PartSerializer, Sink}, Error}; +use crate::{ + error::Error, + ser::part::{PartSerializer, Sink}, +}; pub struct ValueSink<'input, 'key, 'target, Target> where @@ -21,14 +26,12 @@ where urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, ) -> Self { - ValueSink { - urlencoder: urlencoder, - key: key, - } + ValueSink { urlencoder, key } } } -impl<'input, 'key, 'target, Target> Sink for ValueSink<'input, 'key, 'target, Target> +impl<'input, 'key, 'target, Target> Sink + for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { diff --git a/tests/test_deserialize.rs b/tests/test_deserialize.rs index c40a03cc..082468a5 100644 --- a/tests/test_deserialize.rs +++ b/tests/test_deserialize.rs @@ -86,3 +86,114 @@ fn deserialize_unit_enum() { fn deserialize_unit_type() { assert_eq!(serde_urlencoded::from_str(""), Ok(())); } + +#[derive(Debug, Deserialize, PartialEq)] +struct Wrapper { + item: T, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct NewStruct { + list: Vec, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct Struct { + list: Vec>, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct NumList { + list: Vec, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct ListStruct { + list: Vec>, +} + +#[derive(Debug, PartialEq, Deserialize)] +struct MapStruct { + a: usize, + b: String, + c: Option, +} + +#[test] +fn deserialize_mapstruct() { + let de = MapStruct { + a: 10, + b: "Hello".into(), + c: None, + }; + assert_eq!( + de, + serde_urlencoded::from_str::("a=10&b=Hello").unwrap() + ); +} + +#[test] +fn deserialize_newstruct() { + let de = NewStruct { + list: vec!["hello".into(), "world".into()], + }; + assert_eq!( + de, + serde_urlencoded::from_str::("list=hello&list=world") + .unwrap() + ); +} + +#[test] +fn deserialize_numlist() { + let de = NumList { + list: vec![1, 2, 3, 4], + }; + assert_eq!( + de, + serde_urlencoded::from_str::("list=1&list=2&list=3&list=4") + .unwrap() + ); +} + +#[test] +fn deserialize_vec_bool() { + assert_eq!( + Wrapper { + item: vec![true, false, false] + }, + serde_urlencoded::from_str::>( + "item=true&item=false&item=false" + ) + .unwrap() + ); +} + +#[test] +fn deserialize_vec_string() { + assert_eq!( + Wrapper { + item: vec![ + "hello".to_string(), + "matrix".to_string(), + "hello".to_string() + ], + }, + serde_urlencoded::from_str::>( + "item=hello&item=matrix&item=hello" + ) + .unwrap() + ); +} + +#[test] +fn deserialize_struct_unit_enum() { + let result = Wrapper { + item: vec![X::A, X::B, X::C], + }; + + assert_eq!( + serde_urlencoded::from_str("item=A&item=B&item=C"), + Ok(result) + ); +} diff --git a/tests/test_serialize.rs b/tests/test_serialize.rs index 630b6d9f..7a0f6571 100644 --- a/tests/test_serialize.rs +++ b/tests/test_serialize.rs @@ -3,17 +3,6 @@ use serde::Serialize; #[derive(Serialize)] struct NewType(T); -#[derive(Serialize)] -struct NewStruct { - list: Vec, -} - -#[test] -fn serialize_newstruct() { - let s = NewStruct { list: vec![ "hello".into() ] }; - println!("{:?}", serde_urlencoded::to_string(s)); -} - #[test] fn serialize_newtype_i32() { let params = &[("field", Some(NewType(11)))]; @@ -95,3 +84,111 @@ fn serialize_unit_struct() { fn serialize_unit_type() { assert_eq!(serde_urlencoded::to_string(()), Ok("".to_owned())); } + +#[derive(Serialize)] +struct Wrapper { + item: T, +} + +#[derive(Serialize)] +struct NewStruct { + list: Vec, +} + +#[derive(Serialize)] +struct Struct { + list: Vec>, +} + +#[derive(Serialize)] +struct ListStruct { + list: Vec>, +} + +#[test] +fn serialize_newstruct() { + let s = NewStruct { + list: vec!["hello".into(), "world".into()], + }; + assert_eq!( + "list=hello&list=world".to_string(), + serde_urlencoded::to_string(s).unwrap() + ); +} + +#[test] +fn serialize_vec_bool() { + let params = Wrapper { + item: vec![true, false, false], + }; + assert_eq!( + serde_urlencoded::to_string(params).unwrap(), + "item=true&item=false&item=false".to_owned() + ); +} + +#[test] +fn serialize_vec_num() { + let params = Wrapper { + item: vec![0, 1, 2], + }; + assert_eq!( + serde_urlencoded::to_string(params).unwrap(), + "item=0&item=1&item=2".to_owned() + ); +} + +#[test] +fn serialize_vec_str() { + let params = Wrapper { + item: vec!["hello", "world", "hello"], + }; + assert_eq!( + serde_urlencoded::to_string(params).unwrap(), + "item=hello&item=world&item=hello".to_owned() + ); +} + +#[test] +fn serialize_struct_opt() { + let s = Struct { + list: vec![Some("hello".into()), Some("world".into())], + }; + assert_eq!( + "list=hello&list=world".to_string(), + serde_urlencoded::to_string(s).unwrap() + ); +} + +#[test] +fn serialize_struct_newtype() { + let s = ListStruct { + list: vec![NewType(0), NewType(1)], + }; + assert_eq!( + "list=0&list=1".to_string(), + serde_urlencoded::to_string(s).unwrap() + ); +} + +#[test] +fn serialize_struct_unit_enum() { + let params = Wrapper { + item: vec![X::A, X::B, X::C], + }; + assert_eq!( + serde_urlencoded::to_string(params), + Ok("item=A&item=B&item=C".to_owned()) + ); +} + +#[test] +fn serialize_map() { + let mut s = std::collections::BTreeMap::new(); + s.insert("hello", "world"); + s.insert("seri", "alize"); + s.insert("matrix", "ruma"); + + let encoded = serde_urlencoded::to_string(s).unwrap(); + assert_eq!("hello=world&matrix=ruma&seri=alize", encoded); +} From c6359d1916ea6e359bc823691bd3ad922a4cd2d2 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 10:09:19 +0200 Subject: [PATCH 55/95] Integrate serde_urlencoded fork --- Cargo.toml | 9 +- LICENSE | 3 +- README.md | 8 + urlencoded/rustfmt.toml => rustfmt.toml | 0 src/lib.rs | 1 + urlencoded/src/lib.rs => src/urlencoded.rs | 0 {urlencoded/src => src/urlencoded}/de.rs | 4 +- {urlencoded/src => src/urlencoded}/error.rs | 0 .../src/ser/mod.rs => src/urlencoded/ser.rs | 4 +- {urlencoded/src => src/urlencoded}/ser/key.rs | 2 +- .../src => src/urlencoded}/ser/pair.rs | 2 +- .../src => src/urlencoded}/ser/part.rs | 2 +- .../src => src/urlencoded}/ser/value.rs | 2 +- .../url_deserialize.rs | 56 +++--- .../url_serialize.rs | 36 ++-- urlencoded/.gitignore | 2 - urlencoded/.travis.yml | 8 - urlencoded/LICENSE-APACHE | 176 ------------------ urlencoded/LICENSE-MIT | 25 --- urlencoded/README.md | 50 ----- urlencoded/bors.toml | 1 - 21 files changed, 62 insertions(+), 329 deletions(-) create mode 100644 README.md rename urlencoded/rustfmt.toml => rustfmt.toml (100%) rename urlencoded/src/lib.rs => src/urlencoded.rs (100%) rename {urlencoded/src => src/urlencoded}/de.rs (98%) rename {urlencoded/src => src/urlencoded}/error.rs (100%) rename urlencoded/src/ser/mod.rs => src/urlencoded/ser.rs (99%) rename {urlencoded/src => src/urlencoded}/ser/key.rs (97%) rename {urlencoded/src => src/urlencoded}/ser/pair.rs (99%) rename {urlencoded/src => src/urlencoded}/ser/part.rs (99%) rename {urlencoded/src => src/urlencoded}/ser/value.rs (98%) rename urlencoded/tests/test_deserialize.rs => tests/url_deserialize.rs (65%) rename urlencoded/tests/test_serialize.rs => tests/url_serialize.rs (77%) delete mode 100644 urlencoded/.gitignore delete mode 100644 urlencoded/.travis.yml delete mode 100644 urlencoded/LICENSE-APACHE delete mode 100644 urlencoded/LICENSE-MIT delete mode 100644 urlencoded/README.md delete mode 100644 urlencoded/bors.toml diff --git a/Cargo.toml b/Cargo.toml index 1a4a25a8..7f4f0bb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,15 +6,16 @@ license = "MIT" authors = [ "Jonas Platte ", "Isaiah Inuwa ", + "Anthony Ramine ", ] version = "0.1.0" repository = "https://github.com/ruma/ruma-serde" edition = "2018" [dependencies] +dtoa = "0.4.5" js_int = { version = "0.1.4", features = ["serde"] } -serde = "1.0.106" -serde_json = "1.0.51" - -[dev-dependencies] +itoa = "0.4.5" serde = { version = "1.0.106", features = ["derive"] } +serde_json = "1.0.51" +url = "2.1.1" diff --git a/LICENSE b/LICENSE index 4d376442..08c4bbeb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2016 Jimmy Cuadra +Copyright (c) 2016 - 2019 Anthony Ramine +Copyright (c) 2020 Jonas Platte Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 00000000..7102b30a --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# ruma-serde + +This crate contains (de)serialization helpers for other ruma crates. + +Part of that is a fork of serde_urlencoded, with support for sequences in `Deserialize` / +`Serialize` structs (e.g. `Vec`) that are (de)serialized as `field=val1&field=val2` +(instead of the more common `field[]=val1&field[]=val2` format supported by other crates like +`serde_qs`). diff --git a/urlencoded/rustfmt.toml b/rustfmt.toml similarity index 100% rename from urlencoded/rustfmt.toml rename to rustfmt.toml diff --git a/src/lib.rs b/src/lib.rs index 555909aa..88ff7356 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod duration; pub mod json_string; pub mod time; +pub mod urlencoded; pub fn is_default(val: &T) -> bool { val == &T::default() diff --git a/urlencoded/src/lib.rs b/src/urlencoded.rs similarity index 100% rename from urlencoded/src/lib.rs rename to src/urlencoded.rs diff --git a/urlencoded/src/de.rs b/src/urlencoded/de.rs similarity index 98% rename from urlencoded/src/de.rs rename to src/urlencoded/de.rs index 7861f5d4..9dcc9df4 100644 --- a/urlencoded/src/de.rs +++ b/src/urlencoded/de.rs @@ -23,7 +23,7 @@ pub use serde::de::value::Error; /// ]; /// /// assert_eq!( -/// serde_urlencoded::from_bytes::>( +/// ruma_serde::urlencoded::from_bytes::>( /// b"bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), /// Ok(meal)); /// ``` @@ -45,7 +45,7 @@ where /// ]; /// /// assert_eq!( -/// serde_urlencoded::from_str::>( +/// ruma_serde::urlencoded::from_str::>( /// "bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter"), /// Ok(meal)); /// ``` diff --git a/urlencoded/src/error.rs b/src/urlencoded/error.rs similarity index 100% rename from urlencoded/src/error.rs rename to src/urlencoded/error.rs diff --git a/urlencoded/src/ser/mod.rs b/src/urlencoded/ser.rs similarity index 99% rename from urlencoded/src/ser/mod.rs rename to src/urlencoded/ser.rs index 5f4d820f..4e84a8e4 100644 --- a/urlencoded/src/ser/mod.rs +++ b/src/urlencoded/ser.rs @@ -12,7 +12,7 @@ use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; -use crate::error::{Error, Result}; +use crate::urlencoded::error::{Error, Result}; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// @@ -25,7 +25,7 @@ use crate::error::{Error, Result}; /// ]; /// /// assert_eq!( -/// serde_urlencoded::to_string(meal), +/// ruma_serde::urlencoded::to_string(meal), /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); /// ``` pub fn to_string(input: T) -> Result { diff --git a/urlencoded/src/ser/key.rs b/src/urlencoded/ser/key.rs similarity index 97% rename from urlencoded/src/ser/key.rs rename to src/urlencoded/ser/key.rs index 1906d4b4..32f433ac 100644 --- a/urlencoded/src/ser/key.rs +++ b/src/urlencoded/ser/key.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, ops::Deref}; use serde::Serialize; -use crate::ser::{part::Sink, Error}; +use super::{part::Sink, Error}; pub enum Key<'key> { Static(&'static str), diff --git a/urlencoded/src/ser/pair.rs b/src/urlencoded/ser/pair.rs similarity index 99% rename from urlencoded/src/ser/pair.rs rename to src/urlencoded/ser/pair.rs index 82ba3481..3c769ba8 100644 --- a/urlencoded/src/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -7,7 +7,7 @@ use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; -use crate::{ +use crate::urlencoded::{ error::{Error, Result}, ser::{key::KeySink, part::PartSerializer, value::ValueSink}, }; diff --git a/urlencoded/src/ser/part.rs b/src/urlencoded/ser/part.rs similarity index 99% rename from urlencoded/src/ser/part.rs rename to src/urlencoded/ser/part.rs index 514d4a27..fe7e6d7c 100644 --- a/urlencoded/src/ser/part.rs +++ b/src/urlencoded/ser/part.rs @@ -4,7 +4,7 @@ use dtoa; use itoa; use serde::ser; -use crate::error::Error; +use crate::urlencoded::error::Error; pub struct PartSerializer { sink: S, } diff --git a/urlencoded/src/ser/value.rs b/src/urlencoded/ser/value.rs similarity index 98% rename from urlencoded/src/ser/value.rs rename to src/urlencoded/ser/value.rs index a34238ad..e8db4576 100644 --- a/urlencoded/src/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -5,7 +5,7 @@ use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; -use crate::{ +use crate::urlencoded::{ error::Error, ser::part::{PartSerializer, Sink}, }; diff --git a/urlencoded/tests/test_deserialize.rs b/tests/url_deserialize.rs similarity index 65% rename from urlencoded/tests/test_deserialize.rs rename to tests/url_deserialize.rs index 082468a5..291b6bf6 100644 --- a/urlencoded/tests/test_deserialize.rs +++ b/tests/url_deserialize.rs @@ -1,3 +1,4 @@ +use ruma_serde::urlencoded; use serde::Deserialize; #[derive(Deserialize, Debug, PartialEq)] @@ -7,31 +8,28 @@ struct NewType(T); fn deserialize_newtype_i32() { let result = vec![("field".to_owned(), NewType(11))]; - assert_eq!(serde_urlencoded::from_str("field=11"), Ok(result)); + assert_eq!(urlencoded::from_str("field=11"), Ok(result)); } #[test] fn deserialize_bytes() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; - assert_eq!( - serde_urlencoded::from_bytes(b"first=23&last=42"), - Ok(result) - ); + assert_eq!(urlencoded::from_bytes(b"first=23&last=42"), Ok(result)); } #[test] fn deserialize_str() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; - assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); + assert_eq!(urlencoded::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_borrowed_str() { let result = vec![("first", 23), ("last", 42)]; - assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); + assert_eq!(urlencoded::from_str("first=23&last=42"), Ok(result)); } #[test] @@ -39,7 +37,7 @@ fn deserialize_reader() { let result = vec![("first".to_owned(), 23), ("last".to_owned(), 42)]; assert_eq!( - serde_urlencoded::from_reader(b"first=23&last=42" as &[_]), + urlencoded::from_reader(b"first=23&last=42" as &[_]), Ok(result) ); } @@ -50,15 +48,15 @@ fn deserialize_option() { ("first".to_owned(), Some(23)), ("last".to_owned(), Some(42)), ]; - assert_eq!(serde_urlencoded::from_str("first=23&last=42"), Ok(result)); + assert_eq!(urlencoded::from_str("first=23&last=42"), Ok(result)); } #[test] fn deserialize_unit() { - assert_eq!(serde_urlencoded::from_str(""), Ok(())); - assert_eq!(serde_urlencoded::from_str("&"), Ok(())); - assert_eq!(serde_urlencoded::from_str("&&"), Ok(())); - assert!(serde_urlencoded::from_str::<()>("first=23").is_err()); + assert_eq!(urlencoded::from_str(""), Ok(())); + assert_eq!(urlencoded::from_str("&"), Ok(())); + assert_eq!(urlencoded::from_str("&&"), Ok(())); + assert!(urlencoded::from_str::<()>("first=23").is_err()); } #[derive(Deserialize, Debug, PartialEq, Eq)] @@ -76,15 +74,12 @@ fn deserialize_unit_enum() { ("three".to_owned(), X::C), ]; - assert_eq!( - serde_urlencoded::from_str("one=A&two=B&three=C"), - Ok(result) - ); + assert_eq!(urlencoded::from_str("one=A&two=B&three=C"), Ok(result)); } #[test] fn deserialize_unit_type() { - assert_eq!(serde_urlencoded::from_str(""), Ok(())); + assert_eq!(urlencoded::from_str(""), Ok(())); } #[derive(Debug, Deserialize, PartialEq)] @@ -128,7 +123,7 @@ fn deserialize_mapstruct() { }; assert_eq!( de, - serde_urlencoded::from_str::("a=10&b=Hello").unwrap() + urlencoded::from_str::("a=10&b=Hello").unwrap() ); } @@ -139,8 +134,7 @@ fn deserialize_newstruct() { }; assert_eq!( de, - serde_urlencoded::from_str::("list=hello&list=world") - .unwrap() + urlencoded::from_str::("list=hello&list=world").unwrap() ); } @@ -151,8 +145,7 @@ fn deserialize_numlist() { }; assert_eq!( de, - serde_urlencoded::from_str::("list=1&list=2&list=3&list=4") - .unwrap() + urlencoded::from_str::("list=1&list=2&list=3&list=4").unwrap() ); } @@ -162,10 +155,8 @@ fn deserialize_vec_bool() { Wrapper { item: vec![true, false, false] }, - serde_urlencoded::from_str::>( - "item=true&item=false&item=false" - ) - .unwrap() + urlencoded::from_str::>("item=true&item=false&item=false") + .unwrap() ); } @@ -179,10 +170,8 @@ fn deserialize_vec_string() { "hello".to_string() ], }, - serde_urlencoded::from_str::>( - "item=hello&item=matrix&item=hello" - ) - .unwrap() + urlencoded::from_str::>("item=hello&item=matrix&item=hello") + .unwrap() ); } @@ -192,8 +181,5 @@ fn deserialize_struct_unit_enum() { item: vec![X::A, X::B, X::C], }; - assert_eq!( - serde_urlencoded::from_str("item=A&item=B&item=C"), - Ok(result) - ); + assert_eq!(urlencoded::from_str("item=A&item=B&item=C"), Ok(result)); } diff --git a/urlencoded/tests/test_serialize.rs b/tests/url_serialize.rs similarity index 77% rename from urlencoded/tests/test_serialize.rs rename to tests/url_serialize.rs index 7a0f6571..ead5dd93 100644 --- a/urlencoded/tests/test_serialize.rs +++ b/tests/url_serialize.rs @@ -1,3 +1,4 @@ +use ruma_serde::urlencoded; use serde::Serialize; #[derive(Serialize)] @@ -6,10 +7,7 @@ struct NewType(T); #[test] fn serialize_newtype_i32() { let params = &[("field", Some(NewType(11)))]; - assert_eq!( - serde_urlencoded::to_string(params), - Ok("field=11".to_owned()) - ); + assert_eq!(urlencoded::to_string(params), Ok("field=11".to_owned())); } #[test] @@ -17,7 +15,7 @@ fn serialize_option_map_int() { let params = &[("first", Some(23)), ("middle", None), ("last", Some(42))]; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("first=23&last=42".to_owned()) ); } @@ -31,7 +29,7 @@ fn serialize_option_map_string() { ]; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("first=hello&last=world".to_owned()) ); } @@ -41,7 +39,7 @@ fn serialize_option_map_bool() { let params = &[("one", Some(true)), ("two", Some(false))]; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("one=true&two=false".to_owned()) ); } @@ -51,7 +49,7 @@ fn serialize_map_bool() { let params = &[("one", true), ("two", false)]; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("one=true&two=false".to_owned()) ); } @@ -67,7 +65,7 @@ enum X { fn serialize_unit_enum() { let params = &[("one", X::A), ("two", X::B), ("three", X::C)]; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("one=A&two=B&three=C".to_owned()) ); } @@ -77,12 +75,12 @@ struct Unit; #[test] fn serialize_unit_struct() { - assert_eq!(serde_urlencoded::to_string(Unit), Ok("".to_owned())); + assert_eq!(urlencoded::to_string(Unit), Ok("".to_owned())); } #[test] fn serialize_unit_type() { - assert_eq!(serde_urlencoded::to_string(()), Ok("".to_owned())); + assert_eq!(urlencoded::to_string(()), Ok("".to_owned())); } #[derive(Serialize)] @@ -112,7 +110,7 @@ fn serialize_newstruct() { }; assert_eq!( "list=hello&list=world".to_string(), - serde_urlencoded::to_string(s).unwrap() + urlencoded::to_string(s).unwrap() ); } @@ -122,7 +120,7 @@ fn serialize_vec_bool() { item: vec![true, false, false], }; assert_eq!( - serde_urlencoded::to_string(params).unwrap(), + urlencoded::to_string(params).unwrap(), "item=true&item=false&item=false".to_owned() ); } @@ -133,7 +131,7 @@ fn serialize_vec_num() { item: vec![0, 1, 2], }; assert_eq!( - serde_urlencoded::to_string(params).unwrap(), + urlencoded::to_string(params).unwrap(), "item=0&item=1&item=2".to_owned() ); } @@ -144,7 +142,7 @@ fn serialize_vec_str() { item: vec!["hello", "world", "hello"], }; assert_eq!( - serde_urlencoded::to_string(params).unwrap(), + urlencoded::to_string(params).unwrap(), "item=hello&item=world&item=hello".to_owned() ); } @@ -156,7 +154,7 @@ fn serialize_struct_opt() { }; assert_eq!( "list=hello&list=world".to_string(), - serde_urlencoded::to_string(s).unwrap() + urlencoded::to_string(s).unwrap() ); } @@ -167,7 +165,7 @@ fn serialize_struct_newtype() { }; assert_eq!( "list=0&list=1".to_string(), - serde_urlencoded::to_string(s).unwrap() + urlencoded::to_string(s).unwrap() ); } @@ -177,7 +175,7 @@ fn serialize_struct_unit_enum() { item: vec![X::A, X::B, X::C], }; assert_eq!( - serde_urlencoded::to_string(params), + urlencoded::to_string(params), Ok("item=A&item=B&item=C".to_owned()) ); } @@ -189,6 +187,6 @@ fn serialize_map() { s.insert("seri", "alize"); s.insert("matrix", "ruma"); - let encoded = serde_urlencoded::to_string(s).unwrap(); + let encoded = urlencoded::to_string(s).unwrap(); assert_eq!("hello=world&matrix=ruma&seri=alize", encoded); } diff --git a/urlencoded/.gitignore b/urlencoded/.gitignore deleted file mode 100644 index a9d37c56..00000000 --- a/urlencoded/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/urlencoded/.travis.yml b/urlencoded/.travis.yml deleted file mode 100644 index 088c2e49..00000000 --- a/urlencoded/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: rust -rust: - - nightly - - beta - - stable -branches: - except: - - staging.tmp diff --git a/urlencoded/LICENSE-APACHE b/urlencoded/LICENSE-APACHE deleted file mode 100644 index 1b5ec8b7..00000000 --- a/urlencoded/LICENSE-APACHE +++ /dev/null @@ -1,176 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS diff --git a/urlencoded/LICENSE-MIT b/urlencoded/LICENSE-MIT deleted file mode 100644 index 39f6303a..00000000 --- a/urlencoded/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Anthony Ramine - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/urlencoded/README.md b/urlencoded/README.md deleted file mode 100644 index e55a86c2..00000000 --- a/urlencoded/README.md +++ /dev/null @@ -1,50 +0,0 @@ -`x-www-form-urlencoded` meets Serde -=================================== - -This crate is a Rust library for serialising to and deserialising from -the [`application/x-www-form-urlencoded`][urlencoded] format. It is built -upon [Serde], a high performance generic serialization framework and [rust-url], -a URL parser for Rust. - -[rust-url]: https://github.com/servo/rust-url -[Serde]: https://github.com/serde-rs/serde -[urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded - -Installation -============ - -This crate works with Cargo and can be found on -[crates.io] with a `Cargo.toml` like: - -```toml -[dependencies] -serde_urlencoded = "0.5.1" -``` - -[crates.io]: https://crates.io/crates/serde_urlencoded - -## Getting help - -Serde developers live in the #serde channel on -[`irc.mozilla.org`](https://wiki.mozilla.org/IRC) and most rust-url developers -live in the #servo one. The #rust channel is also a good resource with generally -faster response time but less specific knowledge about Serde, rust-url or this -crate. If IRC is not your thing, we are happy to respond to [GitHub -issues](https://github.com/nox/serde_urlencoded/issues/new) as well. - -## License - -serde_urlencoded is licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in serde_urlencoded by you, as defined in the Apache-2.0 license, -shall be dual licensed as above, without any additional terms or conditions. diff --git a/urlencoded/bors.toml b/urlencoded/bors.toml deleted file mode 100644 index 359f8947..00000000 --- a/urlencoded/bors.toml +++ /dev/null @@ -1 +0,0 @@ -status = ["continuous-integration/travis-ci/push"] From 41288b7c73bc0704a2ff73d82c37fa188cceed37 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 10:11:35 +0200 Subject: [PATCH 56/95] Fix warnings --- src/urlencoded/de.rs | 6 +++--- src/urlencoded/ser.rs | 6 ++---- src/urlencoded/ser/key.rs | 2 +- src/urlencoded/ser/pair.rs | 2 +- src/urlencoded/ser/part.rs | 8 +++----- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/urlencoded/de.rs b/src/urlencoded/de.rs index 9dcc9df4..ebdaf315 100644 --- a/src/urlencoded/de.rs +++ b/src/urlencoded/de.rs @@ -133,9 +133,9 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { map.push_back((*field, values)); } let parts = fields - .into_iter() + .iter() .map(|f| Part(Cow::Borrowed(f), None)) - .zip(PartIterator(self.parser).into_iter().map(|(_, mut v)| { + .zip(PartIterator(self.parser).map(|(_, mut v)| { if let Some((_, val)) = map.pop_front() { v.1 = Some(val); } @@ -263,7 +263,7 @@ impl<'de> de::Deserializer<'de> for Part<'de> { where V: de::Visitor<'de>, { - let iter = self.1.ok_or(Error::custom("expected sequence"))?; + let iter = self.1.ok_or_else(|| Error::custom("expected sequence"))?; visitor.visit_seq(SeqDeserializer::new( iter.into_iter().map(|v| Part(v, None)), )) diff --git a/src/urlencoded/ser.rs b/src/urlencoded/ser.rs index 4e84a8e4..71e4db16 100644 --- a/src/urlencoded/ser.rs +++ b/src/urlencoded/ser.rs @@ -54,9 +54,7 @@ impl<'input, 'output, Target: 'output + UrlEncodedTarget> pub fn new( urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, ) -> Self { - Serializer { - urlencoder: urlencoder, - } + Serializer { urlencoder } } } @@ -453,7 +451,7 @@ where value: &T, ) -> Result<()> { { - let key = self.key.as_ref().ok_or_else(|| Error::no_key())?; + let key = self.key.as_ref().ok_or_else(Error::no_key)?; let value_sink = value::ValueSink::new(self.urlencoder, &key); value.serialize(part::PartSerializer::new(value_sink))?; } diff --git a/src/urlencoded/ser/key.rs b/src/urlencoded/ser/key.rs index 32f433ac..6f65ecb4 100644 --- a/src/urlencoded/ser/key.rs +++ b/src/urlencoded/ser/key.rs @@ -38,7 +38,7 @@ where End: for<'key> FnOnce(Key<'key>) -> Result, { pub fn new(end: End) -> Self { - KeySink { end: end } + KeySink { end } } } diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index 3c769ba8..bb5c4118 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -251,7 +251,7 @@ where if result.is_ok() { self.state = PairState::Done; } else { - self.state = PairState::WaitingForValue { key: key }; + self.state = PairState::WaitingForValue { key }; } result }, diff --git a/src/urlencoded/ser/part.rs b/src/urlencoded/ser/part.rs index fe7e6d7c..b58ce43a 100644 --- a/src/urlencoded/ser/part.rs +++ b/src/urlencoded/ser/part.rs @@ -1,7 +1,5 @@ use std::str; -use dtoa; -use itoa; use serde::ser; use crate::urlencoded::error::Error; @@ -11,7 +9,7 @@ pub struct PartSerializer { impl PartSerializer { pub fn new(sink: S) -> Self { - PartSerializer { sink: sink } + PartSerializer { sink } } } @@ -111,7 +109,7 @@ impl ser::Serializer for PartSerializer { } fn serialize_unit_struct(self, name: &'static str) -> Result { - self.sink.serialize_static_str(name.into()) + self.sink.serialize_static_str(name) } fn serialize_unit_variant( @@ -120,7 +118,7 @@ impl ser::Serializer for PartSerializer { _variant_index: u32, variant: &'static str, ) -> Result { - self.sink.serialize_static_str(variant.into()) + self.sink.serialize_static_str(variant) } fn serialize_newtype_struct( From 32d95057a66ff3ac0d8ac98bddde5161f17dcf89 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 12:17:59 +0200 Subject: [PATCH 57/95] cargo fmt --- src/duration/opt_ms.rs | 15 ++++++++++++--- src/duration/secs.rs | 10 ++++++++-- src/time/opt_ms_since_unix_epoch.rs | 15 ++++++++++++--- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/duration/opt_ms.rs b/src/duration/opt_ms.rs index 1e8d6462..f915918a 100644 --- a/src/duration/opt_ms.rs +++ b/src/duration/opt_ms.rs @@ -13,7 +13,10 @@ use serde::{ /// /// Will fail if integer is greater than the maximum integer that can be /// unambiguously represented by an f64. -pub fn serialize(opt_duration: &Option, serializer: S) -> Result +pub fn serialize( + opt_duration: &Option, + serializer: S, +) -> Result where S: Serializer, { @@ -30,7 +33,9 @@ where /// /// Will fail if integer is greater than the maximum integer that can be /// unambiguously represented by an f64. -pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> +pub fn deserialize<'de, D>( + deserializer: D, +) -> Result, D::Error> where D: Deserializer<'de>, { @@ -47,7 +52,11 @@ mod tests { #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] struct DurationTest { - #[serde(with = "super", default, skip_serializing_if = "Option::is_none")] + #[serde( + with = "super", + default, + skip_serializing_if = "Option::is_none" + )] timeout: Option, } diff --git a/src/duration/secs.rs b/src/duration/secs.rs index 830eb4d5..38a091f9 100644 --- a/src/duration/secs.rs +++ b/src/duration/secs.rs @@ -13,7 +13,10 @@ use serde::{ /// /// Will fail if integer is greater than the maximum integer that can be /// unambiguously represented by an f64. -pub fn serialize(duration: &Duration, serializer: S) -> Result +pub fn serialize( + duration: &Duration, + serializer: S, +) -> Result where S: Serializer, { @@ -64,6 +67,9 @@ mod tests { let test = DurationTest { timeout: Duration::from_millis(7000), }; - assert_eq!(serde_json::to_value(test).unwrap(), json!({ "timeout": 7 }),); + assert_eq!( + serde_json::to_value(test).unwrap(), + json!({ "timeout": 7 }), + ); } } diff --git a/src/time/opt_ms_since_unix_epoch.rs b/src/time/opt_ms_since_unix_epoch.rs index 787455ac..8ce9d280 100644 --- a/src/time/opt_ms_since_unix_epoch.rs +++ b/src/time/opt_ms_since_unix_epoch.rs @@ -14,7 +14,10 @@ use serde::{ /// /// Will fail if integer is greater than the maximum integer that can be unambiguously represented /// by an f64. -pub fn serialize(opt_time: &Option, serializer: S) -> Result +pub fn serialize( + opt_time: &Option, + serializer: S, +) -> Result where S: Serializer, { @@ -28,7 +31,9 @@ where /// /// Will fail if integer is greater than the maximum integer that can be unambiguously represented /// by an f64. -pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> +pub fn deserialize<'de, D>( + deserializer: D, +) -> Result, D::Error> where D: Deserializer<'de>, { @@ -45,7 +50,11 @@ mod tests { #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] struct SystemTimeTest { - #[serde(with = "super", default, skip_serializing_if = "Option::is_none")] + #[serde( + with = "super", + default, + skip_serializing_if = "Option::is_none" + )] timestamp: Option, } From 6770ed61c188dc11861d05e4313950cf9edadd78 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 12:28:17 +0200 Subject: [PATCH 58/95] Update .gitignore --- .gitignore | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.gitignore b/.gitignore index 1e4c8083..96ef6c0b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,2 @@ /target - - -#Added by cargo -# -#already existing elements were commented out - -#/target Cargo.lock From 6fa05a1a6fb891550d8c8bdc6715dd4a7f90cde8 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 12:29:44 +0200 Subject: [PATCH 59/95] Update some imports --- src/urlencoded/ser/pair.rs | 4 +--- src/urlencoded/ser/part.rs | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index bb5c4118..9869fb0b 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -1,8 +1,6 @@ -use std::borrow::Cow; -use std::mem; +use std::{borrow::Cow, mem}; use serde::ser; - use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; diff --git a/src/urlencoded/ser/part.rs b/src/urlencoded/ser/part.rs index b58ce43a..1f067c28 100644 --- a/src/urlencoded/ser/part.rs +++ b/src/urlencoded/ser/part.rs @@ -3,6 +3,7 @@ use std::str; use serde::ser; use crate::urlencoded::error::Error; + pub struct PartSerializer { sink: S, } From cb5f8ffc396070055c647a56b3e32f5cc94f5e32 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 12:32:25 +0200 Subject: [PATCH 60/95] Don't use unstable rustfmt options --- rustfmt.toml | 1 - src/urlencoded/ser/pair.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 2b7608b3..7d08e05d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,3 @@ -match_block_trailing_comma = true max_width = 80 newline_style = "Unix" reorder_imports = true diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index 9869fb0b..a8bc7c06 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -239,7 +239,7 @@ where key: value.serialize(key_serializer)?, }; Ok(()) - }, + } PairState::WaitingForValue { key } => { let result = { let value_sink = ValueSink::new(self.urlencoder, &key); @@ -252,7 +252,7 @@ where self.state = PairState::WaitingForValue { key }; } result - }, + } PairState::Done => Err(Error::done()), } } From 1eb5bffbc65fea5e675156bc3b98d1e3b702b6c4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 18:10:29 +0200 Subject: [PATCH 61/95] Add builds.sr.ht manifests --- .builds/beta.yml | 28 ++++++++++++++++++++++++++++ .builds/msrv.yml | 24 ++++++++++++++++++++++++ .builds/nightly.yml | 30 ++++++++++++++++++++++++++++++ .builds/stable.yml | 30 ++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 .builds/beta.yml create mode 100644 .builds/msrv.yml create mode 100644 .builds/nightly.yml create mode 100644 .builds/stable.yml diff --git a/.builds/beta.yml b/.builds/beta.yml new file mode 100644 index 00000000..e6cc8bad --- /dev/null +++ b/.builds/beta.yml @@ -0,0 +1,28 @@ +image: archlinux +packages: + - rustup +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install beta --profile minimal -c rustfmt -c clippy + rustup default beta + - test: | + cd ruma-serde + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --no-default-features --verbose + test1_exit=$? + + cargo test --all-features --verbose + test2_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit )) diff --git a/.builds/msrv.yml b/.builds/msrv.yml new file mode 100644 index 00000000..cd0ed921 --- /dev/null +++ b/.builds/msrv.yml @@ -0,0 +1,24 @@ +image: archlinux +packages: + - rustup +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install 1.36.0 --profile minimal + rustup default 1.36.0 + - test: | + cd ruma-serde + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + # Only make sure the code builds with the MSRV. Tests can require later + # Rust versions, don't compile or run them. + cargo build --no-default-features --verbose + build1_exit=$? + + cargo build --all-features --verbose + build2_exit=$? + + exit $(( $fmt_exit || $build1_exit || $build2_exit )) diff --git a/.builds/nightly.yml b/.builds/nightly.yml new file mode 100644 index 00000000..149821cb --- /dev/null +++ b/.builds/nightly.yml @@ -0,0 +1,30 @@ +image: archlinux +packages: + - rustup +tasks: + - rustup: | + rustup toolchain install nightly --profile minimal + rustup default nightly + + # Try installing rustfmt & clippy for nightly, but don't fail the build + # if they are not available + rustup component add rustfmt || true + rustup component add clippy || true + - test: | + cd ruma-serde + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + if ( rustup component list | grep -q rustfmt ); then + cargo fmt -- --check + fi + fmt_exit=$? + + if ( rustup component list | grep -q clippy ); then + cargo clippy --all-targets --all-features -- -D warnings + fi + clippy_exit=$? + + exit $(( $fmt_exit || $clippy_exit )) diff --git a/.builds/stable.yml b/.builds/stable.yml new file mode 100644 index 00000000..ec85f08f --- /dev/null +++ b/.builds/stable.yml @@ -0,0 +1,30 @@ +image: archlinux +packages: + - rustup +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install stable --profile minimal -c rustfmt -c clippy + rustup default stable + - test: | + cd ruma-serde + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --no-default-features --verbose + test1_exit=$? + + cargo test --all-features --verbose + test2_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit )) + # TODO: Add audit task once cargo-audit binary releases are available. + # See https://github.com/RustSec/cargo-audit/issues/66 From 50218e27ab7c582bf8d25fefc2f8dcf10a58168c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 18:38:37 +0200 Subject: [PATCH 62/95] Add sources to builds.sr.ht manifests --- .builds/beta.yml | 2 ++ .builds/msrv.yml | 2 ++ .builds/nightly.yml | 2 ++ .builds/stable.yml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/.builds/beta.yml b/.builds/beta.yml index e6cc8bad..9179b87a 100644 --- a/.builds/beta.yml +++ b/.builds/beta.yml @@ -1,6 +1,8 @@ image: archlinux packages: - rustup +sources: + - https://github.com/ruma/ruma-serde tasks: - rustup: | # We specify --profile minimal because we'd otherwise download docs diff --git a/.builds/msrv.yml b/.builds/msrv.yml index cd0ed921..ad1b6ea0 100644 --- a/.builds/msrv.yml +++ b/.builds/msrv.yml @@ -1,6 +1,8 @@ image: archlinux packages: - rustup +sources: + - https://github.com/ruma/ruma-serde tasks: - rustup: | # We specify --profile minimal because we'd otherwise download docs diff --git a/.builds/nightly.yml b/.builds/nightly.yml index 149821cb..cd9c0de1 100644 --- a/.builds/nightly.yml +++ b/.builds/nightly.yml @@ -1,6 +1,8 @@ image: archlinux packages: - rustup +sources: + - https://github.com/ruma/ruma-serde tasks: - rustup: | rustup toolchain install nightly --profile minimal diff --git a/.builds/stable.yml b/.builds/stable.yml index ec85f08f..ea1cd2b3 100644 --- a/.builds/stable.yml +++ b/.builds/stable.yml @@ -1,6 +1,8 @@ image: archlinux packages: - rustup +sources: + - https://github.com/ruma/ruma-serde tasks: - rustup: | # We specify --profile minimal because we'd otherwise download docs From 16acf7f75332fb61d7797cf12940724017e26046 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 18:43:49 +0200 Subject: [PATCH 63/95] CI updates --- .builds/msrv.yml | 2 +- .travis.yml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/.builds/msrv.yml b/.builds/msrv.yml index ad1b6ea0..200c20ef 100644 --- a/.builds/msrv.yml +++ b/.builds/msrv.yml @@ -23,4 +23,4 @@ tasks: cargo build --all-features --verbose build2_exit=$? - exit $(( $fmt_exit || $build1_exit || $build2_exit )) + exit $(( $build1_exit || $build2_exit )) diff --git a/.travis.yml b/.travis.yml index 129d203c..4a0863c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,16 +16,8 @@ before_script: if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then rustup component add clippy fi - - | - if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then - cargo install --force cargo-audit - fi - cargo generate-lockfile script: - - | - if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then - cargo audit - fi - cargo fmt -- --check - | if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then From 053d2e94f6c19971d05e99caf3896557b38aec83 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 21:53:42 +0200 Subject: [PATCH 64/95] Update CI config --- .builds/beta.yml | 7 ++----- .builds/msrv.yml | 14 +------------- .builds/stable.yml | 9 +++------ .travis.yml | 29 ----------------------------- README.md | 4 ++++ 5 files changed, 10 insertions(+), 53 deletions(-) delete mode 100644 .travis.yml diff --git a/.builds/beta.yml b/.builds/beta.yml index 9179b87a..e81bd85b 100644 --- a/.builds/beta.yml +++ b/.builds/beta.yml @@ -21,10 +21,7 @@ tasks: cargo clippy --all-targets --all-features -- -D warnings clippy_exit=$? - cargo test --no-default-features --verbose - test1_exit=$? - cargo test --all-features --verbose - test2_exit=$? + test_exit=$? - exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit )) + exit $(( $fmt_exit || $clippy_exit || $test_exit )) diff --git a/.builds/msrv.yml b/.builds/msrv.yml index 200c20ef..a6ea11f0 100644 --- a/.builds/msrv.yml +++ b/.builds/msrv.yml @@ -11,16 +11,4 @@ tasks: - test: | cd ruma-serde - # We don't want the build to stop on individual failure of independent - # tools, so capture tool exit codes and set the task exit code manually - set +e - - # Only make sure the code builds with the MSRV. Tests can require later - # Rust versions, don't compile or run them. - cargo build --no-default-features --verbose - build1_exit=$? - - cargo build --all-features --verbose - build2_exit=$? - - exit $(( $build1_exit || $build2_exit )) + cargo build --verbose diff --git a/.builds/stable.yml b/.builds/stable.yml index ea1cd2b3..0424b9f5 100644 --- a/.builds/stable.yml +++ b/.builds/stable.yml @@ -21,12 +21,9 @@ tasks: cargo clippy --all-targets --all-features -- -D warnings clippy_exit=$? - cargo test --no-default-features --verbose - test1_exit=$? + cargo test --verbose + test_exit=$? - cargo test --all-features --verbose - test2_exit=$? - - exit $(( $fmt_exit || $clippy_exit || $test1_exit || $test2_exit )) + exit $(( $fmt_exit || $clippy_exit || $test_exit )) # TODO: Add audit task once cargo-audit binary releases are available. # See https://github.com/RustSec/cargo-audit/issues/66 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4a0863c2..00000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: "rust" -cache: "cargo" -rust: - - 1.36.0 - - stable - - beta - - nightly -jobs: - allow_failures: - - rust: nightly - fast_finish: true - -before_script: - - rustup component add rustfmt - - | - if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then - rustup component add clippy - fi - - cargo generate-lockfile -script: - - cargo fmt -- --check - - | - if [ "$TRAVIS_RUST_VERSION" != "1.36.0" ]; then - cargo clippy --all-targets --all-features -- -D warnings - fi - - cargo build --verbose - - cargo test --no-default-features --verbose - - cargo test --all-features --verbose -if: "type != push OR (tag IS blank AND branch = master)" diff --git a/README.md b/README.md index 7102b30a..5288aa54 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,7 @@ Part of that is a fork of serde_urlencoded, with support for sequences in `Deser `Serialize` structs (e.g. `Vec`) that are (de)serialized as `field=val1&field=val2` (instead of the more common `field[]=val1&field[]=val2` format supported by other crates like `serde_qs`). + +## Minimum Rust version + +ruma-serde requires Rust 1.36.0 or later. From 7972453e9107d9439e90bf1661538c7b935c3ebb Mon Sep 17 00:00:00 2001 From: "Ragotzy.devin" Date: Wed, 29 Apr 2020 03:58:30 -0400 Subject: [PATCH 65/95] urlencoded: (de)serialize nested structs as JSON --- src/urlencoded/de.rs | 30 ++++++++++++++- src/urlencoded/ser/pair.rs | 58 ++++++++++++++++++++++++++-- tests/url_deserialize.rs | 79 ++++++++++++++++++++++++++++++++++++++ tests/url_serialize.rs | 69 +++++++++++++++++++++++++++++++++ 4 files changed, 230 insertions(+), 6 deletions(-) diff --git a/src/urlencoded/de.rs b/src/urlencoded/de.rs index ebdaf315..003ccf4a 100644 --- a/src/urlencoded/de.rs +++ b/src/urlencoded/de.rs @@ -233,7 +233,11 @@ impl<'de> de::Deserializer<'de> for Part<'de> { where V: de::Visitor<'de>, { - visitor.visit_some(self) + if self.0 == "null" { + visitor.visit_none() + } else { + visitor.visit_some(self) + } } fn deserialize_enum( @@ -269,6 +273,29 @@ impl<'de> de::Deserializer<'de> for Part<'de> { )) } + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + let pairs = self + .1 + .ok_or_else(|| Error::custom("percent decoding may have failed"))?; + + let raw_json = pairs + .get(0) + .ok_or_else(|| Error::custom("no value found for nested struct"))?; + + let mut de = + serde_json::de::Deserializer::from_reader(raw_json.as_bytes()); + de.deserialize_struct(name, fields, visitor) + .map_err(|e| Error::custom(e.to_string())) + } + serde::forward_to_deserialize_any! { char str @@ -278,7 +305,6 @@ impl<'de> de::Deserializer<'de> for Part<'de> { byte_buf unit_struct tuple_struct - struct identifier tuple ignored_any diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index a8bc7c06..ba2e521c 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -32,6 +32,8 @@ pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { state: PairState, key: Option<&'target Cow<'target, str>>, count: &'target mut usize, + len: usize, + json_buf: String, } impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> @@ -48,6 +50,8 @@ where state: PairState::WaitingForKey, key, count, + len: 0, + json_buf: String::new(), } } } @@ -64,7 +68,7 @@ where type SerializeTupleStruct = ser::Impossible<(), Error>; type SerializeTupleVariant = ser::Impossible<(), Error>; type SerializeMap = ser::Impossible<(), Error>; - type SerializeStruct = ser::Impossible<(), Error>; + type SerializeStruct = Self; type SerializeStructVariant = ser::Impossible<(), Error>; serialize_pair! { @@ -177,11 +181,12 @@ where } fn serialize_struct( - self, + mut self, _name: &'static str, - _len: usize, + len: usize, ) -> Result { - Err(Error::unsupported_pair()) + self.len = len; + Ok(self) } fn serialize_struct_variant( @@ -195,6 +200,51 @@ where } } +impl<'input, 'target, Target> ser::SerializeStruct + for PairSerializer<'input, 'target, Target> +where + Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<()> + where + T: ser::Serialize, + { + *self.count += 1; + if self.json_buf.is_empty() { + self.json_buf.push_str("{"); + } + let json_blob = serde_json::to_string(value) + .map_err(|e| Error::Custom(e.to_string().into()))?; + + if *self.count == self.len { + self.json_buf + .push_str(&format!("\"{}\":{}", key, json_blob)); + } else { + self.json_buf + .push_str(&format!("\"{}\":{},", key, json_blob)); + } + Ok(()) + } + + fn end(mut self) -> Result { + use serde::ser::Serialize; + + self.json_buf.push_str("}"); + self.json_buf.serialize(PairSerializer::new( + self.urlencoder, + self.key, + &mut self.count, + )) + } +} + impl<'input, 'target, Target> ser::SerializeSeq for PairSerializer<'input, 'target, Target> where diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index 291b6bf6..4728bfc3 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -1,5 +1,6 @@ use ruma_serde::urlencoded; use serde::Deserialize; +use url::form_urlencoded::Serializer as Encoder; #[derive(Deserialize, Debug, PartialEq)] struct NewType(T); @@ -183,3 +184,81 @@ fn deserialize_struct_unit_enum() { assert_eq!(urlencoded::from_str("item=A&item=B&item=C"), Ok(result)); } + +#[derive(Debug, Deserialize, PartialEq)] +struct Nested { + item: T, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Inner { + c: String, + a: usize, + b: String, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct InnerList { + list: Vec, +} + +#[test] +fn deserialize_nested() { + let mut encoder = Encoder::new(String::new()); + + let nested = Nested { + item: Inner { + c: "hello".into(), + a: 10, + b: "bye".into(), + }, + }; + assert_eq!( + nested, + urlencoded::from_str::>( + &encoder + .append_pair("item", r#"{"c":"hello","a":10,"b":"bye"}"#) + .finish(), + ) + .unwrap() + ); +} + +#[test] +fn deserialize_nested_list() { + let mut encoder = Encoder::new(String::new()); + + let nested = Nested { + item: InnerList { + list: vec![1, 2, 3], + }, + }; + + assert_eq!( + nested, + urlencoded::from_str::>>( + &encoder.append_pair("item", r#"{"list":[1,2,3]}"#).finish(), + ) + .unwrap() + ); +} + +#[test] +fn deserialize_nested_list_option() { + let mut encoder = Encoder::new(String::new()); + + let nested = Nested { + item: InnerList { + list: vec![Some(1), Some(2), None], + }, + }; + assert_eq!( + nested, + urlencoded::from_str::>>>( + &encoder + .append_pair("item", r#"{"list":[1,2,null]}"#) + .finish(), + ) + .unwrap() + ); +} diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index ead5dd93..b9381420 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -1,5 +1,6 @@ use ruma_serde::urlencoded; use serde::Serialize; +use url::form_urlencoded::Serializer as Encoder; #[derive(Serialize)] struct NewType(T); @@ -190,3 +191,71 @@ fn serialize_map() { let encoded = urlencoded::to_string(s).unwrap(); assert_eq!("hello=world&matrix=ruma&seri=alize", encoded); } + +#[derive(Serialize)] +struct Nested { + item: T, +} + +#[derive(Serialize)] +struct Inner { + c: String, + a: usize, + b: String, +} + +#[derive(Debug, Serialize, PartialEq)] +struct InnerList { + list: Vec, +} + +#[test] +fn serialize_nested() { + let mut encoder = Encoder::new(String::new()); + + let s = Nested { + item: Inner { + c: "hello".into(), + a: 10, + b: "bye".into(), + }, + }; + assert_eq!( + encoder + .append_pair("item", r#"{"c":"hello","a":10,"b":"bye"}"#) + .finish(), + urlencoded::to_string(s).unwrap() + ); +} + +#[test] +fn serialize_nested_list() { + let mut encoder = Encoder::new(String::new()); + + let s = Nested { + item: InnerList { + list: vec![1, 2, 3], + }, + }; + assert_eq!( + encoder.append_pair("item", r#"{"list":[1,2,3]}"#).finish(), + urlencoded::to_string(s).unwrap() + ); +} + +#[test] +fn serialize_nested_list_option() { + let mut encoder = Encoder::new(String::new()); + + let s = Nested { + item: InnerList { + list: vec![Some(1), Some(2), None], + }, + }; + assert_eq!( + encoder + .append_pair("item", r#"{"list":[1,2,null]}"#) + .finish(), + urlencoded::to_string(s).unwrap() + ); +} From a22335c6e75b692add2d3f7f51f16f138b958912 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 29 Apr 2020 10:06:07 +0200 Subject: [PATCH 66/95] Remove Cargo.toml left over from serde_urlencoded integration --- urlencoded/Cargo.toml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 urlencoded/Cargo.toml diff --git a/urlencoded/Cargo.toml b/urlencoded/Cargo.toml deleted file mode 100644 index e7ff528c..00000000 --- a/urlencoded/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "serde_urlencoded" -version = "0.6.1" -authors = ["Anthony Ramine "] -license = "MIT/Apache-2.0" -repository = "https://github.com/nox/serde_urlencoded" -documentation = "https://docs.rs/serde_urlencoded" -description = "`x-www-form-urlencoded` meets Serde" -categories = ["encoding", "web-programming"] -keywords = ["serde", "serialization", "urlencoded"] -exclude = ["/.travis.yml", "/bors.toml"] -edition = "2018" - -[badges] -travis-ci = {repository = "nox/serde_urlencoded"} - -[lib] -test = false - -[dependencies] -dtoa = "0.4.5" -itoa = "0.4.5" -serde = { version = "1.0.106", features = ["derive"] } -url = "2.1.1" From a3787cf3b927b18a31c55d3d5d91ec515bfc77c2 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 29 Apr 2020 10:56:19 +0200 Subject: [PATCH 67/95] Update dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f4f0bb0..03e2eea1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ edition = "2018" [dependencies] dtoa = "0.4.5" -js_int = { version = "0.1.4", features = ["serde"] } +js_int = { version = "0.1.5", features = ["serde"] } itoa = "0.4.5" serde = { version = "1.0.106", features = ["derive"] } -serde_json = "1.0.51" +serde_json = "1.0.52" url = "2.1.1" From 1a00c1d386f47a87dba09800dd80311edd4f03c7 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 29 Apr 2020 10:56:45 +0200 Subject: [PATCH 68/95] Don't treat literal "null" as JSON Reverts part of 7972453e9107d9439e90bf1661538c7b935c3ebb --- src/urlencoded/de.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/urlencoded/de.rs b/src/urlencoded/de.rs index 003ccf4a..cc35a0d2 100644 --- a/src/urlencoded/de.rs +++ b/src/urlencoded/de.rs @@ -233,11 +233,7 @@ impl<'de> de::Deserializer<'de> for Part<'de> { where V: de::Visitor<'de>, { - if self.0 == "null" { - visitor.visit_none() - } else { - visitor.visit_some(self) - } + visitor.visit_some(self) } fn deserialize_enum( From f664a0132d76acf810cbb6982aa42f6c5c283463 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 30 Apr 2020 17:23:50 +0200 Subject: [PATCH 69/95] Import some things from ruma-events --- src/empty.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/empty.rs diff --git a/src/empty.rs b/src/empty.rs new file mode 100644 index 00000000..11c71a15 --- /dev/null +++ b/src/empty.rs @@ -0,0 +1,89 @@ +use std::fmt::{self, Formatter}; + +use serde::{ + de::{Deserialize, Deserializer, MapAccess, Visitor}, + ser::{Serialize, SerializeMap, Serializer}, +}; + +/// A meaningless value that serializes to an empty JSON object. +/// +/// This type is used in a few places where the Matrix specification requires an empty JSON object, +/// but it's wasteful to represent it as a `BTreeMap` in Rust code. +#[derive(Clone, Debug, PartialEq)] +pub struct Empty; + +impl Serialize for Empty { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_map(Some(0))?.end() + } +} + +impl<'de> Deserialize<'de> for Empty { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct EmptyMapVisitor; + + impl<'de> Visitor<'de> for EmptyMapVisitor { + type Value = Empty; + + fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "an object/map") + } + + fn visit_map(self, _map: A) -> Result + where + A: MapAccess<'de>, + { + Ok(Empty) + } + } + + deserializer.deserialize_map(EmptyMapVisitor) + } +} + +/// Serde serialization and deserialization functions that map a `Vec` to a +/// `BTreeMap`. +/// +/// The Matrix spec sometimes specifies lists as hash maps so the list entries +/// can be expanded with attributes without breaking compatibility. As that +/// would be a breaking change for ruma's event types anyway, we convert them to +/// `Vec`s for simplicity, using this module. +/// +/// To be used as `#[serde(with = "vec_as_map_of_empty")]`. +pub mod vec_as_map_of_empty { + use std::collections::BTreeMap; + + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + use super::Empty; + + #[allow(clippy::ptr_arg)] + pub fn serialize( + vec: &Vec, + serializer: S, + ) -> Result + where + S: Serializer, + T: Serialize + Eq + Ord, + { + vec.iter() + .map(|v| (v, Empty)) + .collect::>() + .serialize(serializer) + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + T: Deserialize<'de> + Eq + Ord, + { + BTreeMap::::deserialize(deserializer) + .map(|hashmap| hashmap.into_iter().map(|(k, _)| k).collect()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 88ff7356..aff31deb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,65 @@ //! De-/serialization helpers for other ruma crates +use serde::de::{Deserialize, IntoDeserializer}; + pub mod duration; +pub mod empty; pub mod json_string; pub mod time; pub mod urlencoded; +pub use empty::vec_as_map_of_empty; + +/// Check whether a value is equal to its default value. pub fn is_default(val: &T) -> bool { val == &T::default() } + +/// Simply returns `true`. +/// +/// Useful for `#[serde(default = ...)]`. +pub fn default_true() -> bool { + true +} + +/// Serde deserialization decorator to map empty Strings to None, +/// and forward non-empty Strings to the Deserialize implementation for T. +/// Useful for the typical +/// "A room with an X event with an absent, null, or empty Y field +/// should be treated the same as a room with no such event." +/// formulation in the spec. +/// +/// To be used like this: +/// `#[serde(deserialize_with = "empty_string_as_none"]` +/// Relevant serde issue: https://github.com/serde-rs/serde/issues/1425 +pub fn empty_string_as_none<'de, D, T>(de: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, +{ + let opt = Option::::deserialize(de)?; + // TODO: Switch to and remove this attribute `opt.as_deref()` once MSRV is >= 1.40 + #[allow(clippy::option_as_ref_deref, clippy::unknown_clippy_lints)] + let opt = opt.as_ref().map(String::as_str); + match opt { + None | Some("") => Ok(None), + // If T = String, like in m.room.name, the second deserialize is actually superfluous. + // TODO: optimize that somehow? + Some(s) => T::deserialize(s.into_deserializer()).map(Some), + } +} + +#[cfg(test)] +use std::fmt::Debug; + +#[cfg(test)] +use serde::{de::DeserializeOwned, Serialize}; + +#[cfg(test)] +pub fn serde_json_eq(de: T, se: serde_json::Value) +where + T: Clone + Debug + PartialEq + Serialize + DeserializeOwned, +{ + assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); + assert_eq!(de, serde_json::from_value(se).unwrap()); +} From 06f6ca82b284d42a6929200473e3db9f854036f0 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 30 Apr 2020 17:24:09 +0200 Subject: [PATCH 70/95] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 03e2eea1..be1ce5ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.1.0" +version = "0.1.1" repository = "https://github.com/ruma/ruma-serde" edition = "2018" From 3471e9c46ef56dedae218221203c8bdc5034ec5d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 30 Apr 2020 17:55:20 +0200 Subject: [PATCH 71/95] Move serde_json_eq into submodule, always compile --- src/lib.rs | 16 +--------------- src/test.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 15 deletions(-) create mode 100644 src/test.rs diff --git a/src/lib.rs b/src/lib.rs index aff31deb..b0369f6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ use serde::de::{Deserialize, IntoDeserializer}; pub mod duration; pub mod empty; pub mod json_string; +pub mod test; pub mod time; pub mod urlencoded; @@ -48,18 +49,3 @@ where Some(s) => T::deserialize(s.into_deserializer()).map(Some), } } - -#[cfg(test)] -use std::fmt::Debug; - -#[cfg(test)] -use serde::{de::DeserializeOwned, Serialize}; - -#[cfg(test)] -pub fn serde_json_eq(de: T, se: serde_json::Value) -where - T: Clone + Debug + PartialEq + Serialize + DeserializeOwned, -{ - assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); - assert_eq!(de, serde_json::from_value(se).unwrap()); -} diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 00000000..c828bbad --- /dev/null +++ b/src/test.rs @@ -0,0 +1,13 @@ +//! Helpers for tests + +use std::fmt::Debug; + +use serde::{de::DeserializeOwned, Serialize}; + +pub fn serde_json_eq(de: T, se: serde_json::Value) +where + T: Clone + Debug + PartialEq + Serialize + DeserializeOwned, +{ + assert_eq!(se, serde_json::to_value(de.clone()).unwrap()); + assert_eq!(de, serde_json::from_value(se).unwrap()); +} From 2fb17f30be172b5a8d51a5d87c8a961da49fbeb6 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 30 Apr 2020 17:55:36 +0200 Subject: [PATCH 72/95] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index be1ce5ba..009fa195 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.1.1" +version = "0.1.2" repository = "https://github.com/ruma/ruma-serde" edition = "2018" From 25f302f491d5402cc642555a24682f3626c56091 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 1 May 2020 23:33:01 +0200 Subject: [PATCH 73/95] Add is_true --- Cargo.toml | 2 +- src/lib.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 009fa195..2bce54ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.1.2" +version = "0.1.3" repository = "https://github.com/ruma/ruma-serde" edition = "2018" diff --git a/src/lib.rs b/src/lib.rs index b0369f6b..ae83bd69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,13 @@ pub fn default_true() -> bool { true } +/// Simplfy dereferences the given bool. +/// +/// Useful for `#[serde(skip_serializing_if = ...)]` +pub fn is_true(b: &bool) -> bool { + *b +} + /// Serde deserialization decorator to map empty Strings to None, /// and forward non-empty Strings to the Deserialize implementation for T. /// Useful for the typical From d99812364f2a8c12f4593c0cc877879867741ae5 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 4 May 2020 18:38:15 +0200 Subject: [PATCH 74/95] Silence clippy warning --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index ae83bd69..61395efd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,7 @@ pub fn default_true() -> bool { /// Simplfy dereferences the given bool. /// /// Useful for `#[serde(skip_serializing_if = ...)]` +#[allow(clippy::trivially_copy_pass_by_ref)] pub fn is_true(b: &bool) -> bool { *b } From 01562cb7acc4aed8e8ab928054c7590d59b906f3 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 13 May 2020 21:26:54 +0200 Subject: [PATCH 75/95] Revert urlencoded to plain serde_urlencoded logic temporarily --- src/urlencoded.rs | 1 - src/urlencoded/de.rs | 100 +++----------- src/urlencoded/error.rs | 69 ---------- src/urlencoded/ser.rs | 191 ++++++++++++++++---------- src/urlencoded/ser/key.rs | 7 +- src/urlencoded/ser/pair.rs | 262 +++++++++++++++--------------------- src/urlencoded/ser/part.rs | 2 +- src/urlencoded/ser/value.rs | 8 +- tests/url_deserialize.rs | 8 ++ tests/url_serialize.rs | 10 ++ 10 files changed, 270 insertions(+), 388 deletions(-) delete mode 100644 src/urlencoded/error.rs diff --git a/src/urlencoded.rs b/src/urlencoded.rs index ee9ef0c4..9eb39786 100644 --- a/src/urlencoded.rs +++ b/src/urlencoded.rs @@ -1,7 +1,6 @@ //! `x-www-form-urlencoded` meets Serde pub mod de; -pub mod error; pub mod ser; #[doc(inline)] diff --git a/src/urlencoded/de.rs b/src/urlencoded/de.rs index cc35a0d2..0e09beb3 100644 --- a/src/urlencoded/de.rs +++ b/src/urlencoded/de.rs @@ -2,10 +2,9 @@ use std::{borrow::Cow, io::Read}; -use serde::de::{ - self, - value::{MapDeserializer, SeqDeserializer}, - Error as de_Error, IntoDeserializer, +use serde::{ + de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer}, + forward_to_deserialize_any, }; use url::form_urlencoded::{parse, Parse as UrlEncodedParse}; @@ -70,9 +69,9 @@ where from_bytes(&buf) } -/// A deserializer for the Matrix query string format. +/// A deserializer for the `application/x-www-form-urlencoded` format. /// -/// * Supported top-level outputs are structs, maps and sequences, +/// * Supported top-level outputs are structs, maps and sequences of pairs, /// with or without a given length. /// /// * Main `deserialize` methods defers to `deserialize_map`. @@ -80,12 +79,15 @@ where /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'de> { - parser: UrlEncodedParse<'de>, + inner: MapDeserializer<'de, PartIterator<'de>, Error>, } impl<'de> Deserializer<'de> { + /// Returns a new `Deserializer`. pub fn new(parser: UrlEncodedParse<'de>) -> Self { - Self { parser } + Deserializer { + inner: MapDeserializer::new(PartIterator(parser)), + } } } @@ -103,57 +105,25 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { where V: de::Visitor<'de>, { - visitor.visit_map(MapDeserializer::new(PartIterator(self.parser))) + visitor.visit_map(self.inner) } fn deserialize_seq(self, visitor: V) -> Result where V: de::Visitor<'de>, { - visitor.visit_seq(MapDeserializer::new(PartIterator(self.parser))) - } - - fn deserialize_struct( - self, - _name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - let pairs = self.parser.collect::>(); - let mut map = std::collections::VecDeque::new(); - for field in fields { - let values = pairs - .iter() - .filter(|(f, _)| f == field) - .map(|(_f, v)| v.clone()) - .collect::>(); - map.push_back((*field, values)); - } - let parts = fields - .iter() - .map(|f| Part(Cow::Borrowed(f), None)) - .zip(PartIterator(self.parser).map(|(_, mut v)| { - if let Some((_, val)) = map.pop_front() { - v.1 = Some(val); - } - v - })) - .map(|(field, value)| (field, value)); - visitor.visit_map(MapDeserializer::new(parts)) + visitor.visit_seq(self.inner) } fn deserialize_unit(self, visitor: V) -> Result where V: de::Visitor<'de>, { - MapDeserializer::new(PartIterator(self.parser)).end()?; + self.inner.end()?; visitor.visit_unit() } - serde::forward_to_deserialize_any! { + forward_to_deserialize_any! { bool u8 u16 @@ -174,6 +144,7 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { unit_struct newtype_struct tuple_struct + struct identifier tuple enum @@ -187,11 +158,11 @@ impl<'de> Iterator for PartIterator<'de> { type Item = (Part<'de>, Part<'de>); fn next(&mut self) -> Option { - self.0.next().map(|(k, v)| (Part(k, None), Part(v, None))) + self.0.next().map(|(k, v)| (Part(k), Part(v))) } } -struct Part<'de>(Cow<'de, str>, Option>>); +struct Part<'de>(Cow<'de, str>); impl<'de> IntoDeserializer<'de> for Part<'de> { type Deserializer = Self; @@ -259,40 +230,7 @@ impl<'de> de::Deserializer<'de> for Part<'de> { visitor.visit_newtype_struct(self) } - fn deserialize_seq(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - let iter = self.1.ok_or_else(|| Error::custom("expected sequence"))?; - visitor.visit_seq(SeqDeserializer::new( - iter.into_iter().map(|v| Part(v, None)), - )) - } - - fn deserialize_struct( - self, - name: &'static str, - fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - let pairs = self - .1 - .ok_or_else(|| Error::custom("percent decoding may have failed"))?; - - let raw_json = pairs - .get(0) - .ok_or_else(|| Error::custom("no value found for nested struct"))?; - - let mut de = - serde_json::de::Deserializer::from_reader(raw_json.as_bytes()); - de.deserialize_struct(name, fields, visitor) - .map_err(|e| Error::custom(e.to_string())) - } - - serde::forward_to_deserialize_any! { + forward_to_deserialize_any! { char str string @@ -301,9 +239,11 @@ impl<'de> de::Deserializer<'de> for Part<'de> { byte_buf unit_struct tuple_struct + struct identifier tuple ignored_any + seq map } diff --git a/src/urlencoded/error.rs b/src/urlencoded/error.rs deleted file mode 100644 index 32a387cd..00000000 --- a/src/urlencoded/error.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::{borrow::Cow, error, fmt, str}; - -use serde::ser; - -pub type Result = std::result::Result; - -/// Errors returned during serializing to `application/x-www-form-urlencoded`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Error { - Custom(Cow<'static, str>), - Utf8(str::Utf8Error), -} - -impl Error { - pub fn done() -> Self { - Error::Custom("this pair has already been serialized".into()) - } - - pub fn not_done() -> Self { - Error::Custom("this pair has not yet been serialized".into()) - } - - pub fn unsupported_pair() -> Self { - Error::Custom("unsupported pair".into()) - } - - pub fn top_level() -> Self { - let msg = "top-level serializer supports only maps and structs"; - Error::Custom(msg.into()) - } - - pub fn no_key() -> Self { - let msg = "tried to serialize a value before serializing key"; - Error::Custom(msg.into()) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Custom(ref msg) => msg.fmt(f), - Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), - } - } -} - -impl error::Error for Error { - /// The lower-level cause of this error, in the case of a `Utf8` error. - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Custom(_) => None, - Error::Utf8(ref err) => Some(err), - } - } - - /// The lower-level source of this error, in the case of a `Utf8` error. - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - Error::Custom(_) => None, - Error::Utf8(ref err) => Some(err), - } - } -} - -impl ser::Error for Error { - fn custom(msg: T) -> Self { - Error::Custom(format!("{}", msg).into()) - } -} diff --git a/src/urlencoded/ser.rs b/src/urlencoded/ser.rs index 71e4db16..e440ca25 100644 --- a/src/urlencoded/ser.rs +++ b/src/urlencoded/ser.rs @@ -5,14 +5,13 @@ mod pair; mod part; mod value; -use std::{borrow::Cow, str}; - use serde::ser; -use url::form_urlencoded::{ - Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, -}; - -use crate::urlencoded::error::{Error, Result}; +use std::borrow::Cow; +use std::error; +use std::fmt; +use std::str; +use url::form_urlencoded::Serializer as UrlEncodedSerializer; +use url::form_urlencoded::Target as UrlEncodedTarget; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// @@ -28,7 +27,7 @@ use crate::urlencoded::error::{Error, Result}; /// ruma_serde::urlencoded::to_string(meal), /// Ok("bread=baguette&cheese=comt%C3%A9&meat=ham&fat=butter".to_owned())); /// ``` -pub fn to_string(input: T) -> Result { +pub fn to_string(input: T) -> Result { let mut urlencoder = UrlEncodedSerializer::new("".to_owned()); input.serialize(Serializer::new(&mut urlencoder))?; Ok(urlencoder.finish()) @@ -58,11 +57,49 @@ impl<'input, 'output, Target: 'output + UrlEncodedTarget> } } +/// Errors returned during serializing to `application/x-www-form-urlencoded`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Error { + Custom(Cow<'static, str>), + Utf8(str::Utf8Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Custom(ref msg) => msg.fmt(f), + Error::Utf8(ref err) => write!(f, "invalid UTF-8: {}", err), + } + } +} + +impl error::Error for Error { + /// The lower-level cause of this error, in the case of a `Utf8` error. + fn cause(&self) -> Option<&dyn error::Error> { + match *self { + Error::Custom(_) => None, + Error::Utf8(ref err) => Some(err), + } + } + + /// The lower-level source of this error, in the case of a `Utf8` error. + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + Error::Custom(_) => None, + Error::Utf8(ref err) => Some(err), + } + } +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error::Custom(format!("{}", msg).into()) + } +} + /// Sequence serializer. pub struct SeqSerializer<'input, 'output, Target: 'output + UrlEncodedTarget> { urlencoder: &'output mut UrlEncodedSerializer<'input, Target>, - key: Option>, - count: usize, } /// Tuple serializer. @@ -133,82 +170,85 @@ where StructVariantSerializer<'input, 'output, Target>; /// Returns an error. - fn serialize_bool(self, _v: bool) -> Result { + fn serialize_bool(self, _v: bool) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i8(self, _v: i8) -> Result { + fn serialize_i8(self, _v: i8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i16(self, _v: i16) -> Result { + fn serialize_i16(self, _v: i16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i32(self, _v: i32) -> Result { + fn serialize_i32(self, _v: i32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_i64(self, _v: i64) -> Result { + fn serialize_i64(self, _v: i64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u8(self, _v: u8) -> Result { + fn serialize_u8(self, _v: u8) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u16(self, _v: u16) -> Result { + fn serialize_u16(self, _v: u16) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u32(self, _v: u32) -> Result { + fn serialize_u32(self, _v: u32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_u64(self, _v: u64) -> Result { + fn serialize_u64(self, _v: u64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f32(self, _v: f32) -> Result { + fn serialize_f32(self, _v: f32) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_f64(self, _v: f64) -> Result { + fn serialize_f64(self, _v: f64) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_char(self, _v: char) -> Result { + fn serialize_char(self, _v: char) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_str(self, _value: &str) -> Result { + fn serialize_str(self, _value: &str) -> Result { Err(Error::top_level()) } /// Returns an error. - fn serialize_bytes(self, _value: &[u8]) -> Result { + fn serialize_bytes(self, _value: &[u8]) -> Result { Err(Error::top_level()) } /// Returns `Ok`. - fn serialize_unit(self) -> Result { + fn serialize_unit(self) -> Result { Ok(self.urlencoder) } /// Returns `Ok`. - fn serialize_unit_struct(self, _name: &'static str) -> Result { + fn serialize_unit_struct( + self, + _name: &'static str, + ) -> Result { Ok(self.urlencoder) } @@ -218,7 +258,7 @@ where _name: &'static str, _variant_index: u32, _variant: &'static str, - ) -> Result { + ) -> Result { Err(Error::top_level()) } @@ -227,7 +267,7 @@ where self, _name: &'static str, value: &T, - ) -> Result { + ) -> Result { value.serialize(self) } @@ -238,12 +278,12 @@ where _variant_index: u32, _variant: &'static str, _value: &T, - ) -> Result { + ) -> Result { Err(Error::top_level()) } /// Returns `Ok`. - fn serialize_none(self) -> Result { + fn serialize_none(self) -> Result { Ok(self.urlencoder) } @@ -251,21 +291,25 @@ where fn serialize_some( self, value: &T, - ) -> Result { + ) -> Result { value.serialize(self) } /// Serialize a sequence, given length (if any) is ignored. - fn serialize_seq(self, _len: Option) -> Result { + fn serialize_seq( + self, + _len: Option, + ) -> Result { Ok(SeqSerializer { urlencoder: self.urlencoder, - key: None, - count: 0, }) } /// Returns an error. - fn serialize_tuple(self, _len: usize) -> Result { + fn serialize_tuple( + self, + _len: usize, + ) -> Result { Ok(TupleSerializer { urlencoder: self.urlencoder, }) @@ -276,7 +320,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } @@ -287,12 +331,15 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } /// Serializes a map, given length is ignored. - fn serialize_map(self, _len: Option) -> Result { + fn serialize_map( + self, + _len: Option, + ) -> Result { Ok(MapSerializer { urlencoder: self.urlencoder, key: None, @@ -304,7 +351,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Ok(StructSerializer { urlencoder: self.urlencoder, }) @@ -317,7 +364,7 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::top_level()) } } @@ -333,15 +380,11 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<()> { - value.serialize(pair::PairSerializer::new( - self.urlencoder, - self.key.as_ref(), - &mut self.count, - )) + ) -> Result<(), Error> { + value.serialize(pair::PairSerializer::new(self.urlencoder)) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -357,15 +400,11 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<()> { - value.serialize(pair::PairSerializer::new( - self.urlencoder, - None, - &mut 0, - )) + ) -> Result<(), Error> { + value.serialize(pair::PairSerializer::new(self.urlencoder)) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -381,11 +420,11 @@ where fn serialize_field( &mut self, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { self.inner.serialize_field(value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } @@ -401,11 +440,11 @@ where fn serialize_field( &mut self, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { self.inner.serialize_field(value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } @@ -425,7 +464,7 @@ where &mut self, key: &K, value: &V, - ) -> Result<()> { + ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| { let value_sink = value::ValueSink::new(self.urlencoder, &key); value.serialize(part::PartSerializer::new(value_sink))?; @@ -439,7 +478,7 @@ where fn serialize_key( &mut self, key: &T, - ) -> Result<()> { + ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| Ok(key.into())); let key_serializer = part::PartSerializer::new(key_sink); self.key = Some(key.serialize(key_serializer)?); @@ -449,7 +488,7 @@ where fn serialize_value( &mut self, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { { let key = self.key.as_ref().ok_or_else(Error::no_key)?; let value_sink = value::ValueSink::new(self.urlencoder, &key); @@ -459,7 +498,7 @@ where Ok(()) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -476,16 +515,12 @@ where &mut self, key: &'static str, value: &T, - ) -> Result<()> { - let key = Cow::Borrowed(key); - let mut count = 0; - let value_sink = - pair::PairSerializer::new(self.urlencoder, Some(&key), &mut count); - value.serialize(value_sink)?; - Ok(()) + ) -> Result<(), Error> { + let value_sink = value::ValueSink::new(self.urlencoder, key); + value.serialize(part::PartSerializer::new(value_sink)) } - fn end(self) -> Result { + fn end(self) -> Result { Ok(self.urlencoder) } } @@ -502,11 +537,23 @@ where &mut self, key: &'static str, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { self.inner.serialize_field(key, value) } - fn end(self) -> Result { + fn end(self) -> Result { self.inner.end() } } + +impl Error { + fn top_level() -> Self { + let msg = "top-level serializer supports only maps and structs"; + Error::Custom(msg.into()) + } + + fn no_key() -> Self { + let msg = "tried to serialize a value before serializing key"; + Error::Custom(msg.into()) + } +} diff --git a/src/urlencoded/ser/key.rs b/src/urlencoded/ser/key.rs index 6f65ecb4..d2c8a92e 100644 --- a/src/urlencoded/ser/key.rs +++ b/src/urlencoded/ser/key.rs @@ -1,8 +1,7 @@ -use std::{borrow::Cow, ops::Deref}; - -use serde::Serialize; - use super::{part::Sink, Error}; +use serde::Serialize; +use std::borrow::Cow; +use std::ops::Deref; pub enum Key<'key> { Static(&'static str), diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index ba2e521c..01e3f82a 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -1,39 +1,16 @@ -use std::{borrow::Cow, mem}; - +use super::key::KeySink; +use super::part::PartSerializer; +use super::value::ValueSink; +use super::Error; use serde::ser; -use url::form_urlencoded::{ - Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, -}; - -use crate::urlencoded::{ - error::{Error, Result}, - ser::{key::KeySink, part::PartSerializer, value::ValueSink}, -}; - -macro_rules! serialize_pair { - ($($ty:ty => $name:ident,)*) => { - $( - fn $name(self, value: $ty) -> Result<()> { - let key = if let Some(key) = self.key { - key.clone() - } else { - return Err(Error::no_key()); - }; - let value_sink = ValueSink::new(self.urlencoder, &key); - let value_serializer = PartSerializer::new(value_sink); - value_serializer.$name(value) - } - )* - }; -} +use std::borrow::Cow; +use std::mem; +use url::form_urlencoded::Serializer as UrlEncodedSerializer; +use url::form_urlencoded::Target as UrlEncodedTarget; pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, state: PairState, - key: Option<&'target Cow<'target, str>>, - count: &'target mut usize, - len: usize, - json_buf: String, } impl<'input, 'target, Target> PairSerializer<'input, 'target, Target> @@ -42,16 +19,10 @@ where { pub fn new( urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, - key: Option<&'target Cow<'target, str>>, - count: &'target mut usize, ) -> Self { PairSerializer { urlencoder, state: PairState::WaitingForKey, - key, - count, - len: 0, - json_buf: String::new(), } } } @@ -63,39 +34,75 @@ where { type Ok = (); type Error = Error; - type SerializeSeq = Self; + type SerializeSeq = ser::Impossible<(), Error>; type SerializeTuple = Self; type SerializeTupleStruct = ser::Impossible<(), Error>; type SerializeTupleVariant = ser::Impossible<(), Error>; type SerializeMap = ser::Impossible<(), Error>; - type SerializeStruct = Self; + type SerializeStruct = ser::Impossible<(), Error>; type SerializeStructVariant = ser::Impossible<(), Error>; - serialize_pair! { - bool => serialize_bool, - u8 => serialize_u8, - u16 => serialize_u16, - u32 => serialize_u32, - u64 => serialize_u64, - i8 => serialize_i8, - i16 => serialize_i16, - i32 => serialize_i32, - i64 => serialize_i64, - f32 => serialize_f32, - f64 => serialize_f64, - char => serialize_char, - &str => serialize_str, - } - - fn serialize_bytes(self, _value: &[u8]) -> Result<()> { + fn serialize_bool(self, _v: bool) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_unit(self) -> Result<()> { + fn serialize_i8(self, _v: i8) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + fn serialize_i16(self, _v: i16) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i32(self, _v: i32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_i64(self, _v: i64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u8(self, _v: u8) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u16(self, _v: u16) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u32(self, _v: u32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_u64(self, _v: u64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_f32(self, _v: f32) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_f64(self, _v: f64) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_char(self, _v: char) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_str(self, _value: &str) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_unit(self) -> Result<(), Error> { + Err(Error::unsupported_pair()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<(), Error> { Err(Error::unsupported_pair()) } @@ -103,25 +110,16 @@ where self, _name: &'static str, _variant_index: u32, - variant: &'static str, - ) -> Result<()> { - let key = if let Some(key) = self.key { - key.clone() - } else { - let key = Cow::Owned(self.count.to_string()); - *self.count += 1; - key - }; - let value_sink = ValueSink::new(self.urlencoder, &key); - let value_serializer = PartSerializer::new(value_sink); - value_serializer.serialize_str(variant) + _variant: &'static str, + ) -> Result<(), Error> { + Err(Error::unsupported_pair()) } fn serialize_newtype_struct( self, _name: &'static str, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { value.serialize(self) } @@ -131,26 +129,29 @@ where _variant_index: u32, _variant: &'static str, _value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { Err(Error::unsupported_pair()) } - fn serialize_none(self) -> Result<()> { + fn serialize_none(self) -> Result<(), Error> { Ok(()) } fn serialize_some( self, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { value.serialize(self) } - fn serialize_seq(self, _len: Option) -> Result { - Ok(self) + fn serialize_seq( + self, + _len: Option, + ) -> Result { + Err(Error::unsupported_pair()) } - fn serialize_tuple(self, len: usize) -> Result { + fn serialize_tuple(self, len: usize) -> Result { if len == 2 { Ok(self) } else { @@ -162,7 +163,7 @@ where self, _name: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } @@ -172,21 +173,23 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } - fn serialize_map(self, _len: Option) -> Result { + fn serialize_map( + self, + _len: Option, + ) -> Result { Err(Error::unsupported_pair()) } fn serialize_struct( - mut self, + self, _name: &'static str, - len: usize, - ) -> Result { - self.len = len; - Ok(self) + _len: usize, + ) -> Result { + Err(Error::unsupported_pair()) } fn serialize_struct_variant( @@ -195,80 +198,11 @@ where _variant_index: u32, _variant: &'static str, _len: usize, - ) -> Result { + ) -> Result { Err(Error::unsupported_pair()) } } -impl<'input, 'target, Target> ser::SerializeStruct - for PairSerializer<'input, 'target, Target> -where - Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<()> - where - T: ser::Serialize, - { - *self.count += 1; - if self.json_buf.is_empty() { - self.json_buf.push_str("{"); - } - let json_blob = serde_json::to_string(value) - .map_err(|e| Error::Custom(e.to_string().into()))?; - - if *self.count == self.len { - self.json_buf - .push_str(&format!("\"{}\":{}", key, json_blob)); - } else { - self.json_buf - .push_str(&format!("\"{}\":{},", key, json_blob)); - } - Ok(()) - } - - fn end(mut self) -> Result { - use serde::ser::Serialize; - - self.json_buf.push_str("}"); - self.json_buf.serialize(PairSerializer::new( - self.urlencoder, - self.key, - &mut self.count, - )) - } -} - -impl<'input, 'target, Target> ser::SerializeSeq - for PairSerializer<'input, 'target, Target> -where - Target: 'target + UrlEncodedTarget, -{ - type Ok = (); - type Error = Error; - - fn serialize_element( - &mut self, - value: &T, - ) -> Result<()> { - value.serialize(PairSerializer::new( - self.urlencoder, - self.key, - &mut self.count, - )) - } - - fn end(self) -> Result { - Ok(()) - } -} - impl<'input, 'target, Target> ser::SerializeTuple for PairSerializer<'input, 'target, Target> where @@ -280,7 +214,7 @@ where fn serialize_element( &mut self, value: &T, - ) -> Result<()> { + ) -> Result<(), Error> { match mem::replace(&mut self.state, PairState::Done) { PairState::WaitingForKey => { let key_sink = KeySink::new(|key| Ok(key.into())); @@ -307,7 +241,7 @@ where } } - fn end(self) -> Result<()> { + fn end(self) -> Result<(), Error> { if let PairState::Done = self.state { Ok(()) } else { @@ -321,3 +255,17 @@ enum PairState { WaitingForValue { key: Cow<'static, str> }, Done, } + +impl Error { + fn done() -> Self { + Error::Custom("this pair has already been serialized".into()) + } + + fn not_done() -> Self { + Error::Custom("this pair has not yet been serialized".into()) + } + + fn unsupported_pair() -> Self { + Error::Custom("unsupported pair".into()) + } +} diff --git a/src/urlencoded/ser/part.rs b/src/urlencoded/ser/part.rs index 1f067c28..b55f2d15 100644 --- a/src/urlencoded/ser/part.rs +++ b/src/urlencoded/ser/part.rs @@ -2,7 +2,7 @@ use std::str; use serde::ser; -use crate::urlencoded::error::Error; +use super::Error; pub struct PartSerializer { sink: S, diff --git a/src/urlencoded/ser/value.rs b/src/urlencoded/ser/value.rs index e8db4576..37aa3b11 100644 --- a/src/urlencoded/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -1,13 +1,13 @@ use std::str; -use serde::Serialize; +use serde::ser::Serialize; use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; -use crate::urlencoded::{ - error::Error, - ser::part::{PartSerializer, Sink}, +use super::{ + part::{PartSerializer, Sink}, + Error, }; pub struct ValueSink<'input, 'key, 'target, Target> diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index 4728bfc3..2947035b 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -129,6 +129,7 @@ fn deserialize_mapstruct() { } #[test] +#[ignore] fn deserialize_newstruct() { let de = NewStruct { list: vec!["hello".into(), "world".into()], @@ -140,6 +141,7 @@ fn deserialize_newstruct() { } #[test] +#[ignore] fn deserialize_numlist() { let de = NumList { list: vec![1, 2, 3, 4], @@ -151,6 +153,7 @@ fn deserialize_numlist() { } #[test] +#[ignore] fn deserialize_vec_bool() { assert_eq!( Wrapper { @@ -162,6 +165,7 @@ fn deserialize_vec_bool() { } #[test] +#[ignore] fn deserialize_vec_string() { assert_eq!( Wrapper { @@ -177,6 +181,7 @@ fn deserialize_vec_string() { } #[test] +#[ignore] fn deserialize_struct_unit_enum() { let result = Wrapper { item: vec![X::A, X::B, X::C], @@ -203,6 +208,7 @@ struct InnerList { } #[test] +#[ignore] fn deserialize_nested() { let mut encoder = Encoder::new(String::new()); @@ -225,6 +231,7 @@ fn deserialize_nested() { } #[test] +#[ignore] fn deserialize_nested_list() { let mut encoder = Encoder::new(String::new()); @@ -244,6 +251,7 @@ fn deserialize_nested_list() { } #[test] +#[ignore] fn deserialize_nested_list_option() { let mut encoder = Encoder::new(String::new()); diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index b9381420..c818187f 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -105,6 +105,7 @@ struct ListStruct { } #[test] +#[ignore] fn serialize_newstruct() { let s = NewStruct { list: vec!["hello".into(), "world".into()], @@ -116,6 +117,7 @@ fn serialize_newstruct() { } #[test] +#[ignore] fn serialize_vec_bool() { let params = Wrapper { item: vec![true, false, false], @@ -127,6 +129,7 @@ fn serialize_vec_bool() { } #[test] +#[ignore] fn serialize_vec_num() { let params = Wrapper { item: vec![0, 1, 2], @@ -138,6 +141,7 @@ fn serialize_vec_num() { } #[test] +#[ignore] fn serialize_vec_str() { let params = Wrapper { item: vec!["hello", "world", "hello"], @@ -149,6 +153,7 @@ fn serialize_vec_str() { } #[test] +#[ignore] fn serialize_struct_opt() { let s = Struct { list: vec![Some("hello".into()), Some("world".into())], @@ -160,6 +165,7 @@ fn serialize_struct_opt() { } #[test] +#[ignore] fn serialize_struct_newtype() { let s = ListStruct { list: vec![NewType(0), NewType(1)], @@ -171,6 +177,7 @@ fn serialize_struct_newtype() { } #[test] +#[ignore] fn serialize_struct_unit_enum() { let params = Wrapper { item: vec![X::A, X::B, X::C], @@ -210,6 +217,7 @@ struct InnerList { } #[test] +#[ignore] fn serialize_nested() { let mut encoder = Encoder::new(String::new()); @@ -229,6 +237,7 @@ fn serialize_nested() { } #[test] +#[ignore] fn serialize_nested_list() { let mut encoder = Encoder::new(String::new()); @@ -244,6 +253,7 @@ fn serialize_nested_list() { } #[test] +#[ignore] fn serialize_nested_list_option() { let mut encoder = Encoder::new(String::new()); From a9579a47291fae02654c33506092008661a69c14 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 13 May 2020 21:42:16 +0200 Subject: [PATCH 76/95] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2bce54ef..ab6ef797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.1.3" +version = "0.1.4" repository = "https://github.com/ruma/ruma-serde" edition = "2018" From 981a3aebe2978ec6dbbce5f728e6ee805d2574a5 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 13 May 2020 23:00:01 +0200 Subject: [PATCH 77/95] Bump version again to 0.2.0 this time, since the revert to plain serde_urlencoded logic was actually a breaking change --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ab6ef797..bbeb0b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.1.4" +version = "0.2.0" repository = "https://github.com/ruma/ruma-serde" edition = "2018" From e55527fee634b87a9a6e3b09a0533250d3709b60 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 14 May 2020 22:08:55 +0200 Subject: [PATCH 78/95] Merge, re-group imports in urlencoded --- src/urlencoded/ser.rs | 11 +++++------ src/urlencoded/ser/key.rs | 7 ++++--- src/urlencoded/ser/pair.rs | 15 +++++++-------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/urlencoded/ser.rs b/src/urlencoded/ser.rs index e440ca25..874c6b08 100644 --- a/src/urlencoded/ser.rs +++ b/src/urlencoded/ser.rs @@ -5,13 +5,12 @@ mod pair; mod part; mod value; +use std::{borrow::Cow, error, fmt, str}; + use serde::ser; -use std::borrow::Cow; -use std::error; -use std::fmt; -use std::str; -use url::form_urlencoded::Serializer as UrlEncodedSerializer; -use url::form_urlencoded::Target as UrlEncodedTarget; +use url::form_urlencoded::{ + Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, +}; /// Serializes a value into a `application/x-www-form-urlencoded` `String` buffer. /// diff --git a/src/urlencoded/ser/key.rs b/src/urlencoded/ser/key.rs index d2c8a92e..6f65ecb4 100644 --- a/src/urlencoded/ser/key.rs +++ b/src/urlencoded/ser/key.rs @@ -1,7 +1,8 @@ -use super::{part::Sink, Error}; +use std::{borrow::Cow, ops::Deref}; + use serde::Serialize; -use std::borrow::Cow; -use std::ops::Deref; + +use super::{part::Sink, Error}; pub enum Key<'key> { Static(&'static str), diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index 01e3f82a..5e991968 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -1,12 +1,11 @@ -use super::key::KeySink; -use super::part::PartSerializer; -use super::value::ValueSink; -use super::Error; +use std::{borrow::Cow, mem}; + use serde::ser; -use std::borrow::Cow; -use std::mem; -use url::form_urlencoded::Serializer as UrlEncodedSerializer; -use url::form_urlencoded::Target as UrlEncodedTarget; +use url::form_urlencoded::{ + Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, +}; + +use super::{key::KeySink, part::PartSerializer, value::ValueSink, Error}; pub struct PairSerializer<'input, 'target, Target: 'target + UrlEncodedTarget> { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, From 2032fc2a942e8e3139ebb1d45735ecbbb22d6508 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 14 May 2020 22:11:25 +0200 Subject: [PATCH 79/95] impl Sink for `&mut ValueSink` instead of for `ValueSink` preparation for one-key-many-value serialization --- src/urlencoded/ser.rs | 12 ++++++------ src/urlencoded/ser/pair.rs | 4 ++-- src/urlencoded/ser/value.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/urlencoded/ser.rs b/src/urlencoded/ser.rs index 874c6b08..9e6c5846 100644 --- a/src/urlencoded/ser.rs +++ b/src/urlencoded/ser.rs @@ -465,8 +465,8 @@ where value: &V, ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| { - let value_sink = value::ValueSink::new(self.urlencoder, &key); - value.serialize(part::PartSerializer::new(value_sink))?; + let mut value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(&mut value_sink))?; self.key = None; Ok(()) }); @@ -490,8 +490,8 @@ where ) -> Result<(), Error> { { let key = self.key.as_ref().ok_or_else(Error::no_key)?; - let value_sink = value::ValueSink::new(self.urlencoder, &key); - value.serialize(part::PartSerializer::new(value_sink))?; + let mut value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(&mut value_sink))?; } self.key = None; Ok(()) @@ -515,8 +515,8 @@ where key: &'static str, value: &T, ) -> Result<(), Error> { - let value_sink = value::ValueSink::new(self.urlencoder, key); - value.serialize(part::PartSerializer::new(value_sink)) + let mut value_sink = value::ValueSink::new(self.urlencoder, key); + value.serialize(part::PartSerializer::new(&mut value_sink)) } fn end(self) -> Result { diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index 5e991968..c12c404e 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -225,8 +225,8 @@ where } PairState::WaitingForValue { key } => { let result = { - let value_sink = ValueSink::new(self.urlencoder, &key); - let value_serializer = PartSerializer::new(value_sink); + let mut value_sink = ValueSink::new(self.urlencoder, &key); + let value_serializer = PartSerializer::new(&mut value_sink); value.serialize(value_serializer) }; if result.is_ok() { diff --git a/src/urlencoded/ser/value.rs b/src/urlencoded/ser/value.rs index 37aa3b11..344a4280 100644 --- a/src/urlencoded/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -30,8 +30,8 @@ where } } -impl<'input, 'key, 'target, Target> Sink - for ValueSink<'input, 'key, 'target, Target> +impl<'a, 'input, 'key, 'target, Target> Sink + for &'a mut ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { From 0c775de76614f7527bd046b10a9ef5b243f96faa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 14 May 2020 22:16:20 +0200 Subject: [PATCH 80/95] Add serialization support for sequences Sequences of values for one key are serialized as `key=value1&key=value2` --- src/urlencoded/ser/key.rs | 9 +++++++-- src/urlencoded/ser/part.rs | 7 +++++-- src/urlencoded/ser/value.rs | 32 ++++++++++++++++++++++++++++++-- tests/url_serialize.rs | 7 ------- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/urlencoded/ser/key.rs b/src/urlencoded/ser/key.rs index 6f65ecb4..804b4c9c 100644 --- a/src/urlencoded/ser/key.rs +++ b/src/urlencoded/ser/key.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, ops::Deref}; -use serde::Serialize; +use serde::ser; use super::{part::Sink, Error}; @@ -47,6 +47,7 @@ where End: for<'key> FnOnce(Key<'key>) -> Result, { type Ok = Ok; + type SerializeSeq = ser::Impossible; fn serialize_static_str(self, value: &'static str) -> Result { (self.end)(Key::Static(value)) @@ -64,13 +65,17 @@ where Err(self.unsupported()) } - fn serialize_some( + fn serialize_some( self, _value: &T, ) -> Result { Err(self.unsupported()) } + fn serialize_seq(self) -> Result { + Err(self.unsupported()) + } + fn unsupported(self) -> Error { Error::Custom("unsupported key".into()) } diff --git a/src/urlencoded/ser/part.rs b/src/urlencoded/ser/part.rs index b55f2d15..0a4b9de6 100644 --- a/src/urlencoded/ser/part.rs +++ b/src/urlencoded/ser/part.rs @@ -16,6 +16,7 @@ impl PartSerializer { pub trait Sink: Sized { type Ok; + type SerializeSeq: ser::SerializeSeq; fn serialize_static_str( self, @@ -31,13 +32,15 @@ pub trait Sink: Sized { value: &T, ) -> Result; + fn serialize_seq(self) -> Result; + fn unsupported(self) -> Error; } impl ser::Serializer for PartSerializer { type Ok = S::Ok; type Error = Error; - type SerializeSeq = ser::Impossible; + type SerializeSeq = S::SerializeSeq; type SerializeTuple = ser::Impossible; type SerializeTupleStruct = ser::Impossible; type SerializeTupleVariant = ser::Impossible; @@ -155,7 +158,7 @@ impl ser::Serializer for PartSerializer { self, _len: Option, ) -> Result { - Err(self.sink.unsupported()) + self.sink.serialize_seq() } fn serialize_tuple( diff --git a/src/urlencoded/ser/value.rs b/src/urlencoded/ser/value.rs index 344a4280..200e354b 100644 --- a/src/urlencoded/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -1,6 +1,6 @@ use std::str; -use serde::ser::Serialize; +use serde::ser; use url::form_urlencoded::{ Serializer as UrlEncodedSerializer, Target as UrlEncodedTarget, }; @@ -36,6 +36,7 @@ where Target: 'target + UrlEncodedTarget, { type Ok = (); + type SerializeSeq = Self; fn serialize_str(self, value: &str) -> Result<(), Error> { self.urlencoder.append_pair(self.key, value); @@ -54,14 +55,41 @@ where Ok(()) } - fn serialize_some( + fn serialize_some( self, value: &T, ) -> Result { value.serialize(PartSerializer::new(self)) } + fn serialize_seq(self) -> Result { + Ok(self) + } + fn unsupported(self) -> Error { Error::Custom("unsupported value".into()) } } + +impl<'a, 'input, 'key, 'target, Target> ser::SerializeSeq + for &'a mut ValueSink<'input, 'key, 'target, Target> +where + Target: 'target + UrlEncodedTarget, +{ + type Ok = (); + type Error = Error; + + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + value.serialize(PartSerializer::new(&mut **self)) + } + + fn end(self) -> Result { + Ok(()) + } +} diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index c818187f..5a48e931 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -105,7 +105,6 @@ struct ListStruct { } #[test] -#[ignore] fn serialize_newstruct() { let s = NewStruct { list: vec!["hello".into(), "world".into()], @@ -117,7 +116,6 @@ fn serialize_newstruct() { } #[test] -#[ignore] fn serialize_vec_bool() { let params = Wrapper { item: vec![true, false, false], @@ -129,7 +127,6 @@ fn serialize_vec_bool() { } #[test] -#[ignore] fn serialize_vec_num() { let params = Wrapper { item: vec![0, 1, 2], @@ -141,7 +138,6 @@ fn serialize_vec_num() { } #[test] -#[ignore] fn serialize_vec_str() { let params = Wrapper { item: vec!["hello", "world", "hello"], @@ -153,7 +149,6 @@ fn serialize_vec_str() { } #[test] -#[ignore] fn serialize_struct_opt() { let s = Struct { list: vec![Some("hello".into()), Some("world".into())], @@ -165,7 +160,6 @@ fn serialize_struct_opt() { } #[test] -#[ignore] fn serialize_struct_newtype() { let s = ListStruct { list: vec![NewType(0), NewType(1)], @@ -177,7 +171,6 @@ fn serialize_struct_newtype() { } #[test] -#[ignore] fn serialize_struct_unit_enum() { let params = Wrapper { item: vec![X::A, X::B, X::C], From 9092f7d6d83a5268ff01010785fc8301696e350a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 14 May 2020 23:12:12 +0200 Subject: [PATCH 81/95] Update serialization tests --- tests/url_serialize.rs | 81 +++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index 5a48e931..ad293d0f 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -84,86 +84,65 @@ fn serialize_unit_type() { assert_eq!(urlencoded::to_string(()), Ok("".to_owned())); } -#[derive(Serialize)] -struct Wrapper { - item: T, -} - -#[derive(Serialize)] -struct NewStruct { - list: Vec, -} - -#[derive(Serialize)] -struct Struct { - list: Vec>, -} - -#[derive(Serialize)] -struct ListStruct { - list: Vec>, -} - #[test] -fn serialize_newstruct() { - let s = NewStruct { - list: vec!["hello".into(), "world".into()], - }; +fn serialize_list_of_str() { + let s = &[("list", vec!["hello", "world"])]; + assert_eq!( - "list=hello&list=world".to_string(), - urlencoded::to_string(s).unwrap() + urlencoded::to_string(s), + Ok("list=hello&list=world".to_owned()) ); } #[test] -fn serialize_vec_bool() { - let params = Wrapper { - item: vec![true, false, false], +fn serialize_multiple_lists() { + #[derive(Serialize)] + struct Lists { + xs: Vec, + ys: Vec, + } + + let params = Lists { + xs: vec![true, false], + ys: vec![3, 2, 1], }; + assert_eq!( - urlencoded::to_string(params).unwrap(), - "item=true&item=false&item=false".to_owned() + urlencoded::to_string(params), + Ok("xs=true&xs=false&ys=3&ys=2&ys=1".to_owned()) ); } #[test] fn serialize_vec_num() { - let params = Wrapper { - item: vec![0, 1, 2], - }; + let params = [("item", vec![0, 1, 2])]; assert_eq!( - urlencoded::to_string(params).unwrap(), - "item=0&item=1&item=2".to_owned() + urlencoded::to_string(params), + Ok("item=0&item=1&item=2".to_owned()) ); } #[test] fn serialize_vec_str() { - let params = Wrapper { - item: vec!["hello", "world", "hello"], - }; + let params = &[("item", vec!["hello", "world", "hello"])]; assert_eq!( - urlencoded::to_string(params).unwrap(), - "item=hello&item=world&item=hello".to_owned() + urlencoded::to_string(params), + Ok("item=hello&item=world&item=hello".to_owned()) ); } #[test] fn serialize_struct_opt() { - let s = Struct { - list: vec![Some("hello".into()), Some("world".into())], - }; + let s = &[("list", vec![Some("hello"), Some("world")])]; assert_eq!( - "list=hello&list=world".to_string(), - urlencoded::to_string(s).unwrap() + urlencoded::to_string(s), + Ok("list=hello&list=world".to_string()) ); } #[test] fn serialize_struct_newtype() { - let s = ListStruct { - list: vec![NewType(0), NewType(1)], - }; + let s = &[("list", vec![NewType(0), NewType(1)])]; assert_eq!( "list=0&list=1".to_string(), urlencoded::to_string(s).unwrap() @@ -172,9 +151,7 @@ fn serialize_struct_newtype() { #[test] fn serialize_struct_unit_enum() { - let params = Wrapper { - item: vec![X::A, X::B, X::C], - }; + let params = &[("item", vec![X::A, X::B, X::C])]; assert_eq!( urlencoded::to_string(params), Ok("item=A&item=B&item=C".to_owned()) From 7aa27c2a2d34cb9896b1fd36c4817d84d63e71d4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 15 May 2020 00:56:05 +0200 Subject: [PATCH 82/95] More serialization test updates --- Cargo.toml | 3 ++ tests/url_serialize.rs | 72 +++++++++++++----------------------------- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbeb0b44..d0cd7a0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,6 @@ itoa = "0.4.5" serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.52" url = "2.1.1" + +[dev-dependencies] +matches = "0.1.8" diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index ad293d0f..ff9e6cdb 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -1,4 +1,5 @@ -use ruma_serde::urlencoded; +use matches::assert_matches; +use ruma_serde::urlencoded::{self, ser::Error}; use serde::Serialize; use url::form_urlencoded::Serializer as Encoder; @@ -86,10 +87,10 @@ fn serialize_unit_type() { #[test] fn serialize_list_of_str() { - let s = &[("list", vec!["hello", "world"])]; + let params = &[("list", vec!["hello", "world"])]; assert_eq!( - urlencoded::to_string(s), + urlencoded::to_string(params), Ok("list=hello&list=world".to_owned()) ); } @@ -114,43 +115,32 @@ fn serialize_multiple_lists() { } #[test] -fn serialize_vec_num() { - let params = [("item", vec![0, 1, 2])]; +#[ignore] +fn serialize_nested_list() { + let params = &[("list", vec![vec![0u8]])]; + assert_matches!( + urlencoded::to_string(params), + Err(Error::Custom(s)) if s.contains("Unsupported") + ) +} + +#[test] +fn serialize_list_of_option() { + let params = &[("list", vec![Some(10), Some(100)])]; assert_eq!( urlencoded::to_string(params), - Ok("item=0&item=1&item=2".to_owned()) + Ok("list=10&list=100".to_owned()) ); } #[test] -fn serialize_vec_str() { - let params = &[("item", vec!["hello", "world", "hello"])]; - assert_eq!( - urlencoded::to_string(params), - Ok("item=hello&item=world&item=hello".to_owned()) - ); +fn serialize_list_of_newtype() { + let params = &[("list", vec![NewType("test".to_owned())])]; + assert_eq!(urlencoded::to_string(params), Ok("list=test".to_owned())); } #[test] -fn serialize_struct_opt() { - let s = &[("list", vec![Some("hello"), Some("world")])]; - assert_eq!( - urlencoded::to_string(s), - Ok("list=hello&list=world".to_string()) - ); -} - -#[test] -fn serialize_struct_newtype() { - let s = &[("list", vec![NewType(0), NewType(1)])]; - assert_eq!( - "list=0&list=1".to_string(), - urlencoded::to_string(s).unwrap() - ); -} - -#[test] -fn serialize_struct_unit_enum() { +fn serialize_list_of_enum() { let params = &[("item", vec![X::A, X::B, X::C])]; assert_eq!( urlencoded::to_string(params), @@ -208,7 +198,7 @@ fn serialize_nested() { #[test] #[ignore] -fn serialize_nested_list() { +fn serialize_nested_object_with_list() { let mut encoder = Encoder::new(String::new()); let s = Nested { @@ -221,21 +211,3 @@ fn serialize_nested_list() { urlencoded::to_string(s).unwrap() ); } - -#[test] -#[ignore] -fn serialize_nested_list_option() { - let mut encoder = Encoder::new(String::new()); - - let s = Nested { - item: InnerList { - list: vec![Some(1), Some(2), None], - }, - }; - assert_eq!( - encoder - .append_pair("item", r#"{"list":[1,2,null]}"#) - .finish(), - urlencoded::to_string(s).unwrap() - ); -} From 73a46d6b21449165e4921640671c92f80dd78eaa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 15 May 2020 11:45:16 +0200 Subject: [PATCH 83/95] Revert 'impl Sink for `&mut ValueSink` instead of for `ValueSink`' This reverts commit 2032fc2, which was never actually necessary --- src/urlencoded/ser.rs | 12 ++++++------ src/urlencoded/ser/pair.rs | 4 ++-- src/urlencoded/ser/value.rs | 13 ++++++++----- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/urlencoded/ser.rs b/src/urlencoded/ser.rs index 9e6c5846..874c6b08 100644 --- a/src/urlencoded/ser.rs +++ b/src/urlencoded/ser.rs @@ -465,8 +465,8 @@ where value: &V, ) -> Result<(), Error> { let key_sink = key::KeySink::new(|key| { - let mut value_sink = value::ValueSink::new(self.urlencoder, &key); - value.serialize(part::PartSerializer::new(&mut value_sink))?; + let value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(value_sink))?; self.key = None; Ok(()) }); @@ -490,8 +490,8 @@ where ) -> Result<(), Error> { { let key = self.key.as_ref().ok_or_else(Error::no_key)?; - let mut value_sink = value::ValueSink::new(self.urlencoder, &key); - value.serialize(part::PartSerializer::new(&mut value_sink))?; + let value_sink = value::ValueSink::new(self.urlencoder, &key); + value.serialize(part::PartSerializer::new(value_sink))?; } self.key = None; Ok(()) @@ -515,8 +515,8 @@ where key: &'static str, value: &T, ) -> Result<(), Error> { - let mut value_sink = value::ValueSink::new(self.urlencoder, key); - value.serialize(part::PartSerializer::new(&mut value_sink)) + let value_sink = value::ValueSink::new(self.urlencoder, key); + value.serialize(part::PartSerializer::new(value_sink)) } fn end(self) -> Result { diff --git a/src/urlencoded/ser/pair.rs b/src/urlencoded/ser/pair.rs index c12c404e..5e991968 100644 --- a/src/urlencoded/ser/pair.rs +++ b/src/urlencoded/ser/pair.rs @@ -225,8 +225,8 @@ where } PairState::WaitingForValue { key } => { let result = { - let mut value_sink = ValueSink::new(self.urlencoder, &key); - let value_serializer = PartSerializer::new(&mut value_sink); + let value_sink = ValueSink::new(self.urlencoder, &key); + let value_serializer = PartSerializer::new(value_sink); value.serialize(value_serializer) }; if result.is_ok() { diff --git a/src/urlencoded/ser/value.rs b/src/urlencoded/ser/value.rs index 200e354b..f0b3a07e 100644 --- a/src/urlencoded/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -30,8 +30,8 @@ where } } -impl<'a, 'input, 'key, 'target, Target> Sink - for &'a mut ValueSink<'input, 'key, 'target, Target> +impl<'input, 'key, 'target, Target> Sink + for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { @@ -71,8 +71,8 @@ where } } -impl<'a, 'input, 'key, 'target, Target> ser::SerializeSeq - for &'a mut ValueSink<'input, 'key, 'target, Target> +impl<'input, 'key, 'target, Target> ser::SerializeSeq + for ValueSink<'input, 'key, 'target, Target> where Target: 'target + UrlEncodedTarget, { @@ -86,7 +86,10 @@ where where T: ser::Serialize, { - value.serialize(PartSerializer::new(&mut **self)) + value.serialize(PartSerializer::new(ValueSink { + urlencoder: self.urlencoder, + key: self.key, + })) } fn end(self) -> Result { From 338ef529e12e9b334305b3409f050abe96e7e465 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 15 May 2020 11:49:48 +0200 Subject: [PATCH 84/95] Forbid serializing nested lists --- src/urlencoded/ser/value.rs | 14 ++++++++++++-- tests/url_serialize.rs | 3 +-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/urlencoded/ser/value.rs b/src/urlencoded/ser/value.rs index f0b3a07e..08647c32 100644 --- a/src/urlencoded/ser/value.rs +++ b/src/urlencoded/ser/value.rs @@ -16,6 +16,7 @@ where { urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, + nested: bool, } impl<'input, 'key, 'target, Target> ValueSink<'input, 'key, 'target, Target> @@ -26,7 +27,11 @@ where urlencoder: &'target mut UrlEncodedSerializer<'input, Target>, key: &'key str, ) -> Self { - ValueSink { urlencoder, key } + ValueSink { + urlencoder, + key, + nested: false, + } } } @@ -63,7 +68,11 @@ where } fn serialize_seq(self) -> Result { - Ok(self) + if self.nested { + Err(self.unsupported()) + } else { + Ok(self) + } } fn unsupported(self) -> Error { @@ -89,6 +98,7 @@ where value.serialize(PartSerializer::new(ValueSink { urlencoder: self.urlencoder, key: self.key, + nested: true, })) } diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index ff9e6cdb..ad73709d 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -115,12 +115,11 @@ fn serialize_multiple_lists() { } #[test] -#[ignore] fn serialize_nested_list() { let params = &[("list", vec![vec![0u8]])]; assert_matches!( urlencoded::to_string(params), - Err(Error::Custom(s)) if s.contains("Unsupported") + Err(Error::Custom(s)) if s.contains("unsupported") ) } From 17783661daec13a7d2057d4d30abafb04021904c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 15 May 2020 11:50:01 +0200 Subject: [PATCH 85/95] Rename nested struct serialization tests --- tests/url_serialize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/url_serialize.rs b/tests/url_serialize.rs index ad73709d..b0878546 100644 --- a/tests/url_serialize.rs +++ b/tests/url_serialize.rs @@ -177,7 +177,7 @@ struct InnerList { #[test] #[ignore] -fn serialize_nested() { +fn serialize_nested_struct() { let mut encoder = Encoder::new(String::new()); let s = Nested { @@ -197,7 +197,7 @@ fn serialize_nested() { #[test] #[ignore] -fn serialize_nested_object_with_list() { +fn serialize_nested_struct_with_list() { let mut encoder = Encoder::new(String::new()); let s = Nested { From 48c5fb1a73f531caf10c40663fffb3329b05157e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 15 May 2020 11:51:11 +0200 Subject: [PATCH 86/95] Update deps, bump version to 0.2.1 --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d0cd7a0a..46782dd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.2.0" +version = "0.2.1" repository = "https://github.com/ruma/ruma-serde" edition = "2018" @@ -16,8 +16,8 @@ edition = "2018" dtoa = "0.4.5" js_int = { version = "0.1.5", features = ["serde"] } itoa = "0.4.5" -serde = { version = "1.0.106", features = ["derive"] } -serde_json = "1.0.52" +serde = { version = "1.0.110", features = ["derive"] } +serde_json = "1.0.53" url = "2.1.1" [dev-dependencies] From 0e627a8ac1578c43febe88f8eff5e949fe569296 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 17 May 2020 22:02:32 +0200 Subject: [PATCH 87/95] Update url_deserialize tests --- tests/url_deserialize.rs | 105 ++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 58 deletions(-) diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index 2947035b..ee421f25 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -83,19 +83,39 @@ fn deserialize_unit_type() { assert_eq!(urlencoded::from_str(""), Ok(())); } +#[derive(Clone, Copy, Debug, PartialEq, Deserialize)] +struct Params<'a> { + a: usize, + b: &'a str, + c: Option, +} + +#[test] +fn deserialize_struct() { + let de = Params { + a: 10, + b: "Hello", + c: None, + }; + assert_eq!(Ok(de), urlencoded::from_str("a=10&b=Hello")); + assert_eq!(Ok(de), urlencoded::from_str("b=Hello&a=10")); +} + #[derive(Debug, Deserialize, PartialEq)] struct Wrapper { item: T, } #[derive(Debug, PartialEq, Deserialize)] -struct NewStruct { - list: Vec, +struct NewStruct<'a> { + #[serde(borrow)] + list: Vec<&'a str>, } #[derive(Debug, PartialEq, Deserialize)] -struct Struct { - list: Vec>, +struct Struct<'a> { + #[serde(borrow)] + list: Vec>, } #[derive(Debug, PartialEq, Deserialize)] @@ -108,36 +128,13 @@ struct ListStruct { list: Vec>, } -#[derive(Debug, PartialEq, Deserialize)] -struct MapStruct { - a: usize, - b: String, - c: Option, -} - -#[test] -fn deserialize_mapstruct() { - let de = MapStruct { - a: 10, - b: "Hello".into(), - c: None, - }; - assert_eq!( - de, - urlencoded::from_str::("a=10&b=Hello").unwrap() - ); -} - #[test] #[ignore] fn deserialize_newstruct() { let de = NewStruct { - list: vec!["hello".into(), "world".into()], + list: vec!["hello", "world"], }; - assert_eq!( - de, - urlencoded::from_str::("list=hello&list=world").unwrap() - ); + assert_eq!(urlencoded::from_str("list=hello&list=world"), Ok(de)); } #[test] @@ -146,21 +143,17 @@ fn deserialize_numlist() { let de = NumList { list: vec![1, 2, 3, 4], }; - assert_eq!( - de, - urlencoded::from_str::("list=1&list=2&list=3&list=4").unwrap() - ); + assert_eq!(urlencoded::from_str("list=1&list=2&list=3&list=4"), Ok(de)); } #[test] #[ignore] fn deserialize_vec_bool() { assert_eq!( - Wrapper { + urlencoded::from_str("item=true&item=false&item=false"), + Ok(Wrapper { item: vec![true, false, false] - }, - urlencoded::from_str::>("item=true&item=false&item=false") - .unwrap() + }) ); } @@ -168,15 +161,14 @@ fn deserialize_vec_bool() { #[ignore] fn deserialize_vec_string() { assert_eq!( - Wrapper { + urlencoded::from_str("item=hello&item=matrix&item=hello"), + Ok(Wrapper { item: vec![ "hello".to_string(), "matrix".to_string(), "hello".to_string() ], - }, - urlencoded::from_str::>("item=hello&item=matrix&item=hello") - .unwrap() + }) ); } @@ -196,10 +188,10 @@ struct Nested { } #[derive(Debug, Deserialize, PartialEq)] -struct Inner { - c: String, +struct Inner<'a> { + c: &'a str, a: usize, - b: String, + b: &'a str, } #[derive(Debug, Deserialize, PartialEq)] @@ -214,19 +206,18 @@ fn deserialize_nested() { let nested = Nested { item: Inner { - c: "hello".into(), + c: "hello", a: 10, - b: "bye".into(), + b: "bye", }, }; assert_eq!( - nested, - urlencoded::from_str::>( + urlencoded::from_str( &encoder .append_pair("item", r#"{"c":"hello","a":10,"b":"bye"}"#) .finish(), - ) - .unwrap() + ), + Ok(nested) ); } @@ -242,11 +233,10 @@ fn deserialize_nested_list() { }; assert_eq!( - nested, - urlencoded::from_str::>>( + urlencoded::from_str( &encoder.append_pair("item", r#"{"list":[1,2,3]}"#).finish(), - ) - .unwrap() + ), + Ok(nested) ); } @@ -261,12 +251,11 @@ fn deserialize_nested_list_option() { }, }; assert_eq!( - nested, - urlencoded::from_str::>>>( + urlencoded::from_str( &encoder .append_pair("item", r#"{"list":[1,2,null]}"#) .finish(), - ) - .unwrap() + ), + Ok(nested) ); } From e05b30d008cf81ebb729fdd4261748d98173812e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 18 May 2020 01:10:05 +0200 Subject: [PATCH 88/95] Query string deserialization: Allow multiple values for one key --- src/urlencoded/de.rs | 67 ++++++++-- src/urlencoded/de/val_or_vec.rs | 229 ++++++++++++++++++++++++++++++++ tests/url_deserialize.rs | 17 +-- 3 files changed, 291 insertions(+), 22 deletions(-) create mode 100644 src/urlencoded/de/val_or_vec.rs diff --git a/src/urlencoded/de.rs b/src/urlencoded/de.rs index 0e09beb3..a20e0d9a 100644 --- a/src/urlencoded/de.rs +++ b/src/urlencoded/de.rs @@ -1,6 +1,10 @@ //! Deserialization support for the `application/x-www-form-urlencoded` format. -use std::{borrow::Cow, io::Read}; +use std::{ + borrow::Cow, + collections::btree_map::{self, BTreeMap}, + io::Read, +}; use serde::{ de::{self, value::MapDeserializer, Error as de_Error, IntoDeserializer}, @@ -11,14 +15,18 @@ use url::form_urlencoded::{parse, Parse as UrlEncodedParse}; #[doc(inline)] pub use serde::de::value::Error; +mod val_or_vec; + +use val_or_vec::ValOrVec; + /// Deserializes a `application/x-www-form-urlencoded` value from a `&[u8]`. /// /// ``` /// let meal = vec![ /// ("bread".to_owned(), "baguette".to_owned()), /// ("cheese".to_owned(), "comté".to_owned()), -/// ("meat".to_owned(), "ham".to_owned()), /// ("fat".to_owned(), "butter".to_owned()), +/// ("meat".to_owned(), "ham".to_owned()), /// ]; /// /// assert_eq!( @@ -39,8 +47,8 @@ where /// let meal = vec![ /// ("bread".to_owned(), "baguette".to_owned()), /// ("cheese".to_owned(), "comté".to_owned()), -/// ("meat".to_owned(), "ham".to_owned()), /// ("fat".to_owned(), "butter".to_owned()), +/// ("meat".to_owned(), "ham".to_owned()), /// ]; /// /// assert_eq!( @@ -79,14 +87,14 @@ where /// * Everything else but `deserialize_seq` and `deserialize_seq_fixed_size` /// defers to `deserialize`. pub struct Deserializer<'de> { - inner: MapDeserializer<'de, PartIterator<'de>, Error>, + inner: MapDeserializer<'de, EntryIterator<'de>, Error>, } impl<'de> Deserializer<'de> { /// Returns a new `Deserializer`. - pub fn new(parser: UrlEncodedParse<'de>) -> Self { + pub fn new(parse: UrlEncodedParse<'de>) -> Self { Deserializer { - inner: MapDeserializer::new(PartIterator(parser)), + inner: MapDeserializer::new(group_entries(parse).into_iter()), } } } @@ -152,16 +160,53 @@ impl<'de> de::Deserializer<'de> for Deserializer<'de> { } } -struct PartIterator<'de>(UrlEncodedParse<'de>); +fn group_entries<'de>( + parse: UrlEncodedParse<'de>, +) -> BTreeMap, ValOrVec>> { + use btree_map::Entry::*; -impl<'de> Iterator for PartIterator<'de> { - type Item = (Part<'de>, Part<'de>); + let mut res = BTreeMap::new(); - fn next(&mut self) -> Option { - self.0.next().map(|(k, v)| (Part(k), Part(v))) + for (key, value) in parse { + match res.entry(Part(key)) { + Vacant(v) => { + v.insert(ValOrVec::Val(Part(value))); + } + Occupied(mut o) => { + o.get_mut().push(Part(value)); + } + } } + + res } +/* +input: a=b&c=d&a=c + +vvvvv + +next(): a => Wrapper([b, c]) +next(): c => Wrapper([d]) + +struct Foo { + a: Vec, + c: Vec, +} + +struct Bar { + a: Vec, + c: String, +} + +struct Baz { + a: String, +} +*/ + +type EntryIterator<'de> = btree_map::IntoIter, ValOrVec>>; + +#[derive(PartialEq, PartialOrd, Eq, Ord)] struct Part<'de>(Cow<'de, str>); impl<'de> IntoDeserializer<'de> for Part<'de> { diff --git a/src/urlencoded/de/val_or_vec.rs b/src/urlencoded/de/val_or_vec.rs new file mode 100644 index 00000000..6214f4e0 --- /dev/null +++ b/src/urlencoded/de/val_or_vec.rs @@ -0,0 +1,229 @@ +use std::{iter, ptr, vec}; + +use serde::de::{ + self, + value::{Error, SeqDeserializer}, + Deserializer, IntoDeserializer, +}; + +#[derive(Debug)] +pub enum ValOrVec { + Val(T), + Vec(Vec), +} + +impl ValOrVec { + pub fn push(&mut self, new_val: T) { + match self { + Self::Val(val) => { + let mut vec = Vec::with_capacity(2); + // Safety: + // + // since the vec is pre-allocated, push can't panic, so there + // is no opportunity for a panic in the unsafe code. + unsafe { + let existing_val = ptr::read(val); + vec.push(existing_val); + vec.push(new_val); + ptr::write(self, Self::Vec(vec)) + } + } + Self::Vec(vec) => vec.push(new_val), + } + } +} + +impl IntoIterator for ValOrVec { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter::new(self) + } +} + +pub enum IntoIter { + Val(iter::Once), + Vec(vec::IntoIter), +} + +impl IntoIter { + fn new(vv: ValOrVec) -> Self { + match vv { + ValOrVec::Val(val) => Self::Val(iter::once(val)), + ValOrVec::Vec(vec) => Self::Vec(vec.into_iter()), + } + } +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + match self { + Self::Val(iter) => iter.next(), + Self::Vec(iter) => iter.next(), + } + } +} + +impl<'de, T> IntoDeserializer<'de> for ValOrVec +where + T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, +{ + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +macro_rules! forward_to_part { + ($($method:ident,)*) => { + $( + fn $method(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + match self { + Self::Val(val) => val.$method(visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + )* + } +} + +impl<'de, T> Deserializer<'de> for ValOrVec +where + T: IntoDeserializer<'de> + Deserializer<'de, Error = Error>, +{ + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_any(visitor), + Self::Vec(_) => self.deserialize_seq(visitor), + } + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + visitor.visit_seq(SeqDeserializer::new(self.into_iter())) + } + + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_enum(name, variants, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + fn deserialize_tuple( + self, + len: usize, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_tuple(len, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + fn deserialize_struct( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_struct(name, fields, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + fn deserialize_unit_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_unit_struct(name, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + fn deserialize_tuple_struct( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_tuple_struct(name, len, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self { + Self::Val(val) => val.deserialize_newtype_struct(name, visitor), + Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + } + } + + forward_to_part! { + deserialize_bool, + deserialize_char, + deserialize_str, + deserialize_string, + deserialize_bytes, + deserialize_byte_buf, + deserialize_unit, + deserialize_u8, + deserialize_u16, + deserialize_u32, + deserialize_u64, + deserialize_i8, + deserialize_i16, + deserialize_i32, + deserialize_i64, + deserialize_f32, + deserialize_f64, + deserialize_option, + deserialize_identifier, + deserialize_ignored_any, + deserialize_map, + } +} diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index ee421f25..4986b1b1 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -69,13 +69,13 @@ enum X { #[test] fn deserialize_unit_enum() { - let result = vec![ - ("one".to_owned(), X::A), - ("two".to_owned(), X::B), - ("three".to_owned(), X::C), - ]; + let result: Vec<(String, X)> = + urlencoded::from_str("one=A&two=B&three=C").unwrap(); - assert_eq!(urlencoded::from_str("one=A&two=B&three=C"), Ok(result)); + assert_eq!(result.len(), 3); + assert!(result.contains(&("one".to_owned(), X::A))); + assert!(result.contains(&("two".to_owned(), X::B))); + assert!(result.contains(&("three".to_owned(), X::C))); } #[test] @@ -129,7 +129,6 @@ struct ListStruct { } #[test] -#[ignore] fn deserialize_newstruct() { let de = NewStruct { list: vec!["hello", "world"], @@ -138,7 +137,6 @@ fn deserialize_newstruct() { } #[test] -#[ignore] fn deserialize_numlist() { let de = NumList { list: vec![1, 2, 3, 4], @@ -147,7 +145,6 @@ fn deserialize_numlist() { } #[test] -#[ignore] fn deserialize_vec_bool() { assert_eq!( urlencoded::from_str("item=true&item=false&item=false"), @@ -158,7 +155,6 @@ fn deserialize_vec_bool() { } #[test] -#[ignore] fn deserialize_vec_string() { assert_eq!( urlencoded::from_str("item=hello&item=matrix&item=hello"), @@ -173,7 +169,6 @@ fn deserialize_vec_string() { } #[test] -#[ignore] fn deserialize_struct_unit_enum() { let result = Wrapper { item: vec![X::A, X::B, X::C], From af0a304594789447a799ba96d691172208664785 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 19 May 2020 21:59:11 +0200 Subject: [PATCH 89/95] Fix building on 1.36.0 --- src/urlencoded/de/val_or_vec.rs | 48 +++++++++++++++++---------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/urlencoded/de/val_or_vec.rs b/src/urlencoded/de/val_or_vec.rs index 6214f4e0..fbb068c5 100644 --- a/src/urlencoded/de/val_or_vec.rs +++ b/src/urlencoded/de/val_or_vec.rs @@ -15,7 +15,7 @@ pub enum ValOrVec { impl ValOrVec { pub fn push(&mut self, new_val: T) { match self { - Self::Val(val) => { + ValOrVec::Val(val) => { let mut vec = Vec::with_capacity(2); // Safety: // @@ -25,10 +25,10 @@ impl ValOrVec { let existing_val = ptr::read(val); vec.push(existing_val); vec.push(new_val); - ptr::write(self, Self::Vec(vec)) + ptr::write(self, ValOrVec::Vec(vec)) } } - Self::Vec(vec) => vec.push(new_val), + ValOrVec::Vec(vec) => vec.push(new_val), } } } @@ -50,8 +50,8 @@ pub enum IntoIter { impl IntoIter { fn new(vv: ValOrVec) -> Self { match vv { - ValOrVec::Val(val) => Self::Val(iter::once(val)), - ValOrVec::Vec(vec) => Self::Vec(vec.into_iter()), + ValOrVec::Val(val) => IntoIter::Val(iter::once(val)), + ValOrVec::Vec(vec) => IntoIter::Vec(vec.into_iter()), } } } @@ -61,8 +61,8 @@ impl Iterator for IntoIter { fn next(&mut self) -> Option { match self { - Self::Val(iter) => iter.next(), - Self::Vec(iter) => iter.next(), + IntoIter::Val(iter) => iter.next(), + IntoIter::Vec(iter) => iter.next(), } } } @@ -85,8 +85,8 @@ macro_rules! forward_to_part { where V: de::Visitor<'de> { match self { - Self::Val(val) => val.$method(visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.$method(visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } )* @@ -104,8 +104,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_any(visitor), - Self::Vec(_) => self.deserialize_seq(visitor), + ValOrVec::Val(val) => val.deserialize_any(visitor), + ValOrVec::Vec(_) => self.deserialize_seq(visitor), } } @@ -126,8 +126,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_enum(name, variants, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.deserialize_enum(name, variants, visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } @@ -140,8 +140,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_tuple(len, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.deserialize_tuple(len, visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } @@ -155,8 +155,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_struct(name, fields, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.deserialize_struct(name, fields, visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } @@ -169,8 +169,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_unit_struct(name, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.deserialize_unit_struct(name, visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } @@ -184,8 +184,10 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_tuple_struct(name, len, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => { + val.deserialize_tuple_struct(name, len, visitor) + } + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } @@ -198,8 +200,8 @@ where V: de::Visitor<'de>, { match self { - Self::Val(val) => val.deserialize_newtype_struct(name, visitor), - Self::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Val(val) => val.deserialize_newtype_struct(name, visitor), + ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), } } From b5f436d511fa09b27e998fe7b687e599eba35c8c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 19 May 2020 22:22:44 +0200 Subject: [PATCH 90/95] Expand explanation comment for unsafe code --- src/urlencoded/de/val_or_vec.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/urlencoded/de/val_or_vec.rs b/src/urlencoded/de/val_or_vec.rs index fbb068c5..0e8409a0 100644 --- a/src/urlencoded/de/val_or_vec.rs +++ b/src/urlencoded/de/val_or_vec.rs @@ -15,12 +15,17 @@ pub enum ValOrVec { impl ValOrVec { pub fn push(&mut self, new_val: T) { match self { + // To transform a Self::Val into a Self::Vec, we take the existing + // value out via ptr::read and add it to a vector, together with the + // new value. Since setting self to `ValOrVec::Vec` normally would + // cause T's Drop implementation to run if it has one (which would + // free resources that will now be owned by the first vec element), + // we instead use ptr::write to set self to Self::Vec. ValOrVec::Val(val) => { let mut vec = Vec::with_capacity(2); - // Safety: - // - // since the vec is pre-allocated, push can't panic, so there - // is no opportunity for a panic in the unsafe code. + // Safety: since the vec is pre-allocated, push can't panic, so + // there is no opportunity for outside code to observe an + // invalid state of self. unsafe { let existing_val = ptr::read(val); vec.push(existing_val); From 964aae00ff1a5b32986e43c56ec46b166ce185b1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 23 May 2020 18:47:11 +0200 Subject: [PATCH 91/95] Add additional tests to val_or_vec --- src/urlencoded/de/val_or_vec.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/urlencoded/de/val_or_vec.rs b/src/urlencoded/de/val_or_vec.rs index 0e8409a0..ee2c4181 100644 --- a/src/urlencoded/de/val_or_vec.rs +++ b/src/urlencoded/de/val_or_vec.rs @@ -234,3 +234,31 @@ where deserialize_map, } } + +#[cfg(test)] +mod tests { + use std::borrow::Cow; + + use matches::assert_matches; + + use super::ValOrVec; + + #[test] + fn cow_borrowed() { + let mut x = ValOrVec::Val(Cow::Borrowed("a")); + x.push(Cow::Borrowed("b")); + x.push(Cow::Borrowed("c")); + assert_matches!(x, ValOrVec::Vec(v) if v == vec!["a", "b", "c"]); + } + + #[test] + fn cow_owned() { + let mut x = ValOrVec::Val(Cow::from("a".to_owned())); + x.push(Cow::from("b".to_owned())); + x.push(Cow::from("c".to_owned())); + assert_matches!( + x, + ValOrVec::Vec(v) if v == vec!["a".to_owned(), "b".to_owned(), "c".to_owned()] + ); + } +} From 6b60606b300194318cd0388b8cd694425152fe4d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 23 May 2020 18:58:40 +0200 Subject: [PATCH 92/95] Update deserialization error messages --- src/urlencoded/de/val_or_vec.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/urlencoded/de/val_or_vec.rs b/src/urlencoded/de/val_or_vec.rs index ee2c4181..2ed1e0bc 100644 --- a/src/urlencoded/de/val_or_vec.rs +++ b/src/urlencoded/de/val_or_vec.rs @@ -91,7 +91,7 @@ macro_rules! forward_to_part { { match self { ValOrVec::Val(val) => val.$method(visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } )* @@ -132,7 +132,7 @@ where { match self { ValOrVec::Val(val) => val.deserialize_enum(name, variants, visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } @@ -146,7 +146,7 @@ where { match self { ValOrVec::Val(val) => val.deserialize_tuple(len, visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } @@ -161,7 +161,7 @@ where { match self { ValOrVec::Val(val) => val.deserialize_struct(name, fields, visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } @@ -175,7 +175,7 @@ where { match self { ValOrVec::Val(val) => val.deserialize_unit_struct(name, visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } @@ -192,7 +192,7 @@ where ValOrVec::Val(val) => { val.deserialize_tuple_struct(name, len, visitor) } - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } @@ -206,7 +206,7 @@ where { match self { ValOrVec::Val(val) => val.deserialize_newtype_struct(name, visitor), - ValOrVec::Vec(_) => Err(de::Error::custom("TODO: Error message")), + ValOrVec::Vec(_) => Err(de::Error::custom("unsupported value")), } } From 18ba86ac273ac84b944df9e111528737e3b16ee4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 23 May 2020 21:40:42 +0200 Subject: [PATCH 93/95] Update tests/url_deserialize.rs --- tests/url_deserialize.rs | 110 ++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index 4986b1b1..869f10e5 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -1,3 +1,4 @@ +use matches::assert_matches; use ruma_serde::urlencoded; use serde::Deserialize; use url::form_urlencoded::Serializer as Encoder; @@ -97,8 +98,76 @@ fn deserialize_struct() { b: "Hello", c: None, }; - assert_eq!(Ok(de), urlencoded::from_str("a=10&b=Hello")); - assert_eq!(Ok(de), urlencoded::from_str("b=Hello&a=10")); + assert_eq!(urlencoded::from_str("a=10&b=Hello"), Ok(de)); + assert_eq!(urlencoded::from_str("b=Hello&a=10"), Ok(de)); +} + +#[test] +fn deserialize_list_of_str() { + // TODO: It would make sense to support this. + assert_matches!( + urlencoded::from_str::>("a=a&a=b"), + Err(error) if error.to_string().contains("unsupported") + ); + + assert_eq!( + urlencoded::from_str("a=a&a=b"), + Ok(vec![("a", vec!["a", "b"])]) + ) +} + +#[test] +fn deserialize_multiple_lists() { + #[derive(Debug, PartialEq, Deserialize)] + struct Lists { + xs: Vec, + ys: Vec, + } + + assert_eq!( + urlencoded::from_str("xs=true&xs=false&ys=3&ys=2&ys=1"), + Ok(Lists { + xs: vec![true, false], + ys: vec![3, 2, 1], + }) + ); + + assert_eq!( + urlencoded::from_str("ys=3&xs=true&ys=2&xs=false&ys=1"), + Ok(Lists { + xs: vec![true, false], + ys: vec![3, 2, 1], + }) + ); +} + +#[test] +fn deserialize_nested_list() { + assert!(urlencoded::from_str::>)>>("a=b").is_err()); +} + +#[test] +fn deserialize_list_of_option() { + assert_eq!( + urlencoded::from_str("list=10&list=100"), + Ok(vec![("list", vec![Some(10), Some(100)])]) + ); +} + +#[test] +fn deserialize_list_of_newtype() { + assert_eq!( + urlencoded::from_str("list=test"), + Ok(vec![("list", vec![NewType("test")])]) + ); +} + +#[test] +fn deserialize_list_of_enum() { + assert_eq!( + urlencoded::from_str("item=A&item=B&item=C"), + Ok(vec![("item", vec![X::A, X::B, X::C])]) + ); } #[derive(Debug, Deserialize, PartialEq)] @@ -144,39 +213,6 @@ fn deserialize_numlist() { assert_eq!(urlencoded::from_str("list=1&list=2&list=3&list=4"), Ok(de)); } -#[test] -fn deserialize_vec_bool() { - assert_eq!( - urlencoded::from_str("item=true&item=false&item=false"), - Ok(Wrapper { - item: vec![true, false, false] - }) - ); -} - -#[test] -fn deserialize_vec_string() { - assert_eq!( - urlencoded::from_str("item=hello&item=matrix&item=hello"), - Ok(Wrapper { - item: vec![ - "hello".to_string(), - "matrix".to_string(), - "hello".to_string() - ], - }) - ); -} - -#[test] -fn deserialize_struct_unit_enum() { - let result = Wrapper { - item: vec![X::A, X::B, X::C], - }; - - assert_eq!(urlencoded::from_str("item=A&item=B&item=C"), Ok(result)); -} - #[derive(Debug, Deserialize, PartialEq)] struct Nested { item: T, @@ -196,7 +232,7 @@ struct InnerList { #[test] #[ignore] -fn deserialize_nested() { +fn deserialize_nested_struct() { let mut encoder = Encoder::new(String::new()); let nested = Nested { @@ -218,7 +254,7 @@ fn deserialize_nested() { #[test] #[ignore] -fn deserialize_nested_list() { +fn deserialize_nested_struct_with_list() { let mut encoder = Encoder::new(String::new()); let nested = Nested { From 91011be2a004f0c2c9b220e0afa527b7db1bc3a8 Mon Sep 17 00:00:00 2001 From: "Ragotzy.devin" Date: Sat, 23 May 2020 17:41:49 -0400 Subject: [PATCH 94/95] Add test to verify urlencoded deserializer works with serde attributes --- tests/url_deserialize.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/url_deserialize.rs b/tests/url_deserialize.rs index 869f10e5..2f93af17 100644 --- a/tests/url_deserialize.rs +++ b/tests/url_deserialize.rs @@ -141,6 +141,46 @@ fn deserialize_multiple_lists() { ); } +#[test] +fn deserialize_with_serde_attributes() { + use std::time::{Duration, SystemTime, UNIX_EPOCH}; + + #[derive(Debug, PartialEq, Deserialize)] + struct FieldsWithAttributes { + #[serde(default)] + xs: Vec, + #[serde(default)] + def: Option, + #[serde( + default, + deserialize_with = "ruma_serde::time::opt_ms_since_unix_epoch::deserialize" + )] + time: Option, + #[serde(default)] + flag: bool, + } + + assert_eq!( + urlencoded::from_str("xs=true&xs=false&def=3&time=1&flag=true"), + Ok(FieldsWithAttributes { + xs: vec![true, false], + def: Some(3), + time: Some(UNIX_EPOCH + Duration::from_millis(1)), + flag: true, + }) + ); + + assert_eq!( + urlencoded::from_str(""), + Ok(FieldsWithAttributes { + xs: vec![], + def: None, + time: None, + flag: false, + }) + ); +} + #[test] fn deserialize_nested_list() { assert!(urlencoded::from_str::>)>>("a=b").is_err()); From 851ffea6d20bef1c66f1c8e0ceb4d4a00c9804fc Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 23 May 2020 23:51:41 +0200 Subject: [PATCH 95/95] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 46782dd8..aac1ff7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ authors = [ "Isaiah Inuwa ", "Anthony Ramine ", ] -version = "0.2.1" +version = "0.2.2" repository = "https://github.com/ruma/ruma-serde" edition = "2018"