Просмотр исходного кода

Add custom_encoding_override() to form_urlencoded::Serializer.

This is an alternative to `encoding_override()` that can be used
without a dependency on rust-encoding.
Simon Sapin 9 лет назад
Родитель
Сommit
b761d6c236
4 измененных файлов с 50 добавлено и 6 удалено
  1. 1 1
      Cargo.toml
  2. 38 4
      src/form_urlencoded.rs
  3. 1 1
      src/lib.rs
  4. 10 0
      tests/unit.rs

+ 1 - 1
Cargo.toml

@@ -2,7 +2,7 @@
 
 name = "url"
 # When updating version, also modify html_root_url in the lib.rs
-version = "1.5.1"
+version = "1.6.0"
 authors = ["The rust-url developers"]
 
 description = "URL library for Rust, based on the WHATWG URL Standard"

+ 38 - 4
src/form_urlencoded.rs

@@ -16,6 +16,7 @@
 use encoding::EncodingOverride;
 use percent_encoding::{percent_encode_byte, percent_decode};
 use std::borrow::{Borrow, Cow};
+use std::fmt;
 use std::str;
 
 
@@ -216,6 +217,15 @@ pub struct Serializer<T: Target> {
     target: Option<T>,
     start_position: usize,
     encoding: EncodingOverride,
+    custom_encoding: Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>,
+}
+
+struct SilentDebug<T>(T);
+
+impl<T> fmt::Debug for SilentDebug<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str("…")
+    }
 }
 
 pub trait Target {
@@ -272,6 +282,7 @@ impl<T: Target> Serializer<T> {
             target: Some(target),
             start_position: start_position,
             encoding: EncodingOverride::utf8(),
+            custom_encoding: None,
         }
     }
 
@@ -290,11 +301,20 @@ impl<T: Target> Serializer<T> {
         self
     }
 
+    /// Set the character encoding to be used for names and values before percent-encoding.
+    pub fn custom_encoding_override<F>(&mut self, encode: F) -> &mut Self
+        where F: FnMut(&str) -> Cow<[u8]> + 'static
+    {
+        self.custom_encoding = Some(SilentDebug(Box::new(encode)));
+        self
+    }
+
     /// Serialize and append a name/value pair.
     ///
     /// Panics if called after `.finish()`.
     pub fn append_pair(&mut self, name: &str, value: &str) -> &mut Self {
-        append_pair(string(&mut self.target), self.start_position, self.encoding, name, value);
+        append_pair(string(&mut self.target), self.start_position, self.encoding,
+                    &mut self.custom_encoding, name, value);
         self
     }
 
@@ -311,7 +331,8 @@ impl<T: Target> Serializer<T> {
             let string = string(&mut self.target);
             for pair in iter {
                 let &(ref k, ref v) = pair.borrow();
-                append_pair(string, self.start_position, self.encoding, k.as_ref(), v.as_ref());
+                append_pair(string, self.start_position, self.encoding,
+                            &mut self.custom_encoding, k.as_ref(), v.as_ref());
             }
         }
         self
@@ -324,6 +345,8 @@ impl<T: Target> Serializer<T> {
     /// Panics if called after `.finish()`.
     #[cfg(feature = "query_encoding")]
     pub fn append_charset(&mut self) -> &mut Self {
+        assert!(self.custom_encoding.is_none(),
+                "Cannot use both custom_encoding_override() and append_charset()");
         {
             let string = string(&mut self.target);
             append_separator_if_needed(string, self.start_position);
@@ -361,9 +384,20 @@ fn string<T: Target>(target: &mut Option<T>) -> &mut String {
 }
 
 fn append_pair(string: &mut String, start_position: usize, encoding: EncodingOverride,
+               custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>,
                name: &str, value: &str) {
     append_separator_if_needed(string, start_position);
-    string.extend(byte_serialize(&encoding.encode(name.into())));
+    append_encoded(name, string, encoding, custom_encoding);
     string.push('=');
-    string.extend(byte_serialize(&encoding.encode(value.into())));
+    append_encoded(value, string, encoding, custom_encoding);
+}
+
+fn append_encoded(s: &str, string: &mut String, encoding: EncodingOverride,
+               custom_encoding: &mut Option<SilentDebug<Box<FnMut(&str) -> Cow<[u8]>>>>) {
+    let bytes = if let Some(SilentDebug(ref mut custom)) = *custom_encoding {
+        custom(s)
+    } else {
+        encoding.encode(s.into())
+    };
+    string.extend(byte_serialize(&bytes));
 }

+ 1 - 1
src/lib.rs

@@ -104,7 +104,7 @@ assert_eq!(css_url.as_str(), "http://servo.github.io/rust-url/main.css");
 # run().unwrap();
 */
 
-#![doc(html_root_url = "https://docs.rs/url/1.5.1")]
+#![doc(html_root_url = "https://docs.rs/url/1.6.0")]
 
 #[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
 #[macro_use] extern crate matches;

+ 10 - 0
tests/unit.rs

@@ -11,6 +11,7 @@
 #[macro_use]
 extern crate url;
 
+use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::net::{Ipv4Addr, Ipv6Addr};
 use std::path::{Path, PathBuf};
@@ -255,6 +256,15 @@ fn test_form_serialize() {
     assert_eq!(encoded, "foo=%C3%A9%26&bar=&foo=%23");
 }
 
+#[test]
+fn form_urlencoded_custom_encoding_override() {
+    let encoded = form_urlencoded::Serializer::new(String::new())
+        .custom_encoding_override(|s| s.as_bytes().to_ascii_uppercase().into())
+        .append_pair("foo", "bar")
+        .finish();
+    assert_eq!(encoded, "FOO=BAR");
+}
+
 #[test]
 fn host_and_port_display() {
     assert_eq!(