diff --git a/Changelog.md b/Changelog.md index f3e879f0..341cb892 100644 --- a/Changelog.md +++ b/Changelog.md @@ -147,7 +147,7 @@ - [#423]: All escaping functions now accepts and returns strings instead of byte slices - [#423]: Removed `BytesText::from_plain` because it internally did escaping of a byte array, - but since now escaping works on strings. Use `BytesText::from_plain_str` instead + but since now escaping works on strings. Use `BytesText::new` instead - [#428]: Removed `BytesText::escaped()`. Use `.as_ref()` provided by `Deref` impl instead. - [#428]: Removed `BytesText::from_escaped()`. Use constructors from strings instead, @@ -159,6 +159,22 @@ - [#428]: Removed `Decoder` parameter from `_and_decode` versions of functions for `BytesText` (remember, that those functions was renamed in #415). +- [#431]: Changed event constructors: + |Old names |New name + |--------------------------------------------------|---------------------------------------------- + |`BytesStart::owned_name(impl Into>)` |`BytesStart::new(impl Into>)` + |`BytesStart::borrowed_name(&[u8])` |_(as above)_ + |`BytesStart::owned(impl Into>, usize)` |`BytesStart::from_content(impl Into>, usize)` + |`BytesStart::borrowed(&[u8], usize)` |_(as above)_ + |`BytesEnd::owned(Vec)` |`BytesEnd::new(impl Into>)` + |`BytesEnd::borrowed(&[u8])` |_(as above)_ + |`BytesText::from_escaped(impl Into>)` |`BytesText::from_escaped(impl Into>)` + |`BytesText::from_escaped_str(impl Into>)`|_(as above)_ + |`BytesText::from_plain(&[u8])` |`BytesText::new(&str)` + |`BytesText::from_plain_str(&str)` |_(as above)_ + |`BytesCData::new(impl Into>)` |`BytesCData::new(impl Into>)` + |`BytesCData::from_str(&str)` |_(as above)_ + ### New Tests - [#9]: Added tests for incorrect nested tags in input @@ -190,6 +206,7 @@ [#421]: https://github.com/tafia/quick-xml/pull/421 [#423]: https://github.com/tafia/quick-xml/pull/423 [#428]: https://github.com/tafia/quick-xml/pull/428 +[#431]: https://github.com/tafia/quick-xml/pull/431 [#434]: https://github.com/tafia/quick-xml/pull/434 [#437]: https://github.com/tafia/quick-xml/pull/437 diff --git a/README.md b/README.md index 12451f32..26499d58 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ loop { // crates a new element ... alternatively we could reuse `e` by calling // `e.into_owned()` - let mut elem = BytesStart::owned_name("my_elem"); + let mut elem = BytesStart::new("my_elem"); // collect existing attributes elem.extend_attributes(e.attributes().map(|attr| attr.unwrap())); @@ -92,7 +92,7 @@ loop { assert!(writer.write_event(Event::Start(elem)).is_ok()); }, Ok(Event::End(e)) if e.name().as_ref() == b"this_tag" => { - assert!(writer.write_event(Event::End(BytesEnd::borrowed("my_elem"))).is_ok()); + assert!(writer.write_event(Event::End(BytesEnd::new("my_elem"))).is_ok()); }, Ok(Event::Eof) => break, // we can either move or borrow the event to write, depending on your use-case diff --git a/src/de/mod.rs b/src/de/mod.rs index 31b717c3..caabbdf8 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -1041,11 +1041,8 @@ mod tests { assert_eq!(de.read, vec![]); assert_eq!(de.write, vec![]); - assert_eq!(de.next().unwrap(), Start(BytesStart::borrowed_name("root"))); - assert_eq!( - de.peek().unwrap(), - &Start(BytesStart::borrowed_name("inner")) - ); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("root"))); + assert_eq!(de.peek().unwrap(), &Start(BytesStart::new("inner"))); // Should skip first tree de.skip().unwrap(); @@ -1053,11 +1050,11 @@ mod tests { assert_eq!( de.write, vec![ - Start(BytesStart::borrowed_name("inner")), - Text(BytesText::from_escaped_str("text")), - Start(BytesStart::borrowed_name("inner")), - End(BytesEnd::borrowed("inner")), - End(BytesEnd::borrowed("inner")), + Start(BytesStart::new("inner")), + Text(BytesText::from_escaped("text")), + Start(BytesStart::new("inner")), + End(BytesEnd::new("inner")), + End(BytesEnd::new("inner")), ] ); @@ -1069,8 +1066,8 @@ mod tests { // // // - assert_eq!(de.next().unwrap(), Start(BytesStart::borrowed_name("next"))); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("next"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("next"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("next"))); // We finish writing. Next call to `next()` should start replay that messages: // @@ -1087,27 +1084,24 @@ mod tests { assert_eq!( de.read, vec![ - Start(BytesStart::borrowed_name("inner")), - Text(BytesText::from_escaped_str("text")), - Start(BytesStart::borrowed_name("inner")), - End(BytesEnd::borrowed("inner")), - End(BytesEnd::borrowed("inner")), + Start(BytesStart::new("inner")), + Text(BytesText::from_escaped("text")), + Start(BytesStart::new("inner")), + End(BytesEnd::new("inner")), + End(BytesEnd::new("inner")), ] ); assert_eq!(de.write, vec![]); - assert_eq!( - de.next().unwrap(), - Start(BytesStart::borrowed_name("inner")) - ); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner"))); // Skip `#text` node and consume after it de.skip().unwrap(); assert_eq!( de.read, vec![ - Start(BytesStart::borrowed_name("inner")), - End(BytesEnd::borrowed("inner")), - End(BytesEnd::borrowed("inner")), + Start(BytesStart::new("inner")), + End(BytesEnd::new("inner")), + End(BytesEnd::new("inner")), ] ); assert_eq!( @@ -1115,15 +1109,12 @@ mod tests { vec![ // This comment here to keep the same formatting of both arrays // otherwise rustfmt suggest one-line it - Text(BytesText::from_escaped_str("text")), + Text(BytesText::from_escaped("text")), ] ); - assert_eq!( - de.next().unwrap(), - Start(BytesStart::borrowed_name("inner")) - ); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("inner"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("inner"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner"))); // We finish writing. Next call to `next()` should start replay messages: // @@ -1138,22 +1129,16 @@ mod tests { assert_eq!( de.read, vec![ - Text(BytesText::from_escaped_str("text")), - End(BytesEnd::borrowed("inner")), + Text(BytesText::from_escaped("text")), + End(BytesEnd::new("inner")), ] ); assert_eq!(de.write, vec![]); - assert_eq!( - de.next().unwrap(), - Text(BytesText::from_escaped_str("text")) - ); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("inner"))); - assert_eq!( - de.next().unwrap(), - Start(BytesStart::borrowed_name("target")) - ); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("target"))); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("root"))); + assert_eq!(de.next().unwrap(), Text(BytesText::from_escaped("text"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("inner"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("target"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("target"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("root"))); } /// Checks that `read_to_end()` behaves correctly after `skip()` @@ -1177,7 +1162,7 @@ mod tests { assert_eq!(de.read, vec![]); assert_eq!(de.write, vec![]); - assert_eq!(de.next().unwrap(), Start(BytesStart::borrowed_name("root"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("root"))); // Skip the tree de.skip().unwrap(); @@ -1185,11 +1170,11 @@ mod tests { assert_eq!( de.write, vec![ - Start(BytesStart::borrowed_name("skip")), - Text(BytesText::from_escaped_str("text")), - Start(BytesStart::borrowed_name("skip")), - End(BytesEnd::borrowed("skip")), - End(BytesEnd::borrowed("skip")), + Start(BytesStart::new("skip")), + Text(BytesText::from_escaped("text")), + Start(BytesStart::new("skip")), + End(BytesEnd::new("skip")), + End(BytesEnd::new("skip")), ] ); @@ -1200,20 +1185,17 @@ mod tests { // // // - assert_eq!( - de.next().unwrap(), - Start(BytesStart::borrowed_name("target")) - ); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("target"))); de.read_to_end(QName(b"target")).unwrap(); assert_eq!(de.read, vec![]); assert_eq!( de.write, vec![ - Start(BytesStart::borrowed_name("skip")), - Text(BytesText::from_escaped_str("text")), - Start(BytesStart::borrowed_name("skip")), - End(BytesEnd::borrowed("skip")), - End(BytesEnd::borrowed("skip")), + Start(BytesStart::new("skip")), + Text(BytesText::from_escaped("text")), + Start(BytesStart::new("skip")), + End(BytesEnd::new("skip")), + End(BytesEnd::new("skip")), ] ); @@ -1231,19 +1213,19 @@ mod tests { assert_eq!( de.read, vec![ - Start(BytesStart::borrowed_name("skip")), - Text(BytesText::from_escaped_str("text")), - Start(BytesStart::borrowed_name("skip")), - End(BytesEnd::borrowed("skip")), - End(BytesEnd::borrowed("skip")), + Start(BytesStart::new("skip")), + Text(BytesText::from_escaped("text")), + Start(BytesStart::new("skip")), + End(BytesEnd::new("skip")), + End(BytesEnd::new("skip")), ] ); assert_eq!(de.write, vec![]); - assert_eq!(de.next().unwrap(), Start(BytesStart::borrowed_name("skip"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("skip"))); de.read_to_end(QName(b"skip")).unwrap(); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("root"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("root"))); } /// Checks that limiting buffer size works correctly @@ -1293,31 +1275,25 @@ mod tests { "#, ); - assert_eq!(de.next().unwrap(), Start(BytesStart::borrowed_name("root"))); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("root"))); assert_eq!( de.next().unwrap(), - Start(BytesStart::borrowed(r#"tag a="1""#, 3)) + Start(BytesStart::from_content(r#"tag a="1""#, 3)) ); assert_eq!(de.read_to_end(QName(b"tag")).unwrap(), ()); assert_eq!( de.next().unwrap(), - Start(BytesStart::borrowed(r#"tag a="2""#, 3)) + Start(BytesStart::from_content(r#"tag a="2""#, 3)) ); - assert_eq!( - de.next().unwrap(), - CData(BytesCData::from_str("cdata content")) - ); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("tag"))); + assert_eq!(de.next().unwrap(), CData(BytesCData::new("cdata content"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("tag"))); - assert_eq!( - de.next().unwrap(), - Start(BytesStart::borrowed_name("self-closed")) - ); + assert_eq!(de.next().unwrap(), Start(BytesStart::new("self-closed"))); assert_eq!(de.read_to_end(QName(b"self-closed")).unwrap(), ()); - assert_eq!(de.next().unwrap(), End(BytesEnd::borrowed("root"))); + assert_eq!(de.next().unwrap(), End(BytesEnd::new("root"))); assert_eq!(de.next().unwrap(), Eof); } @@ -1385,18 +1361,18 @@ mod tests { assert_eq!( events, vec![ - Start(BytesStart::borrowed( + Start(BytesStart::from_content( r#"item name="hello" source="world.rs""#, 4 )), - Text(BytesText::from_escaped_str("Some text")), - End(BytesEnd::borrowed("item")), - Start(BytesStart::borrowed("item2", 5)), - End(BytesEnd::borrowed("item2")), - Start(BytesStart::borrowed("item3", 5)), - End(BytesEnd::borrowed("item3")), - Start(BytesStart::borrowed(r#"item4 value="world" "#, 5)), - End(BytesEnd::borrowed("item4")), + Text(BytesText::from_escaped("Some text")), + End(BytesEnd::new("item")), + Start(BytesStart::from_content("item2", 5)), + End(BytesEnd::new("item2")), + Start(BytesStart::from_content("item3", 5)), + End(BytesEnd::new("item3")), + Start(BytesStart::from_content(r#"item4 value="world" "#, 5)), + End(BytesEnd::new("item4")), ] ) } @@ -1416,7 +1392,7 @@ mod tests { assert_eq!( reader.next().unwrap(), - DeEvent::Start(BytesStart::borrowed("item ", 4)) + DeEvent::Start(BytesStart::from_content("item ", 4)) ); reader.read_to_end(QName(b"item")).unwrap(); assert_eq!(reader.next().unwrap(), DeEvent::Eof); diff --git a/src/de/seq.rs b/src/de/seq.rs index 2539d0a8..8dc9a462 100644 --- a/src/de/seq.rs +++ b/src/de/seq.rs @@ -134,7 +134,7 @@ where #[test] fn test_not_in() { - let tag = BytesStart::borrowed_name("tag"); + let tag = BytesStart::new("tag"); assert_eq!(not_in(&[], &tag, Decoder::utf8()).unwrap(), true); assert_eq!( diff --git a/src/events/mod.rs b/src/events/mod.rs index a3a67b24..6181a40b 100644 --- a/src/events/mod.rs +++ b/src/events/mod.rs @@ -54,6 +54,9 @@ use attributes::{Attribute, Attributes}; /// /// In well-formed XML it could contain a Byte-Order-Mark (BOM). If this event /// contains something else except BOM, the XML should be considered ill-formed. +/// +/// This is a reader-only event. If you need to write a text before the first tag, +/// use the [`BytesText`] event. #[derive(Debug, Clone, Eq, PartialEq)] pub struct BytesStartText<'a> { content: BytesText<'a>, @@ -138,52 +141,35 @@ impl<'a> BytesStart<'a> { } } - /// Creates a new `BytesStart` from the given content (name + attributes). + /// Creates a new `BytesStart` from the given name. /// /// # Warning /// - /// `&content[..name_len]` is not checked to be a valid name + /// `name` must be a valid name. #[inline] - pub fn borrowed(content: &'a str, name_len: usize) -> Self { + pub fn new>>(name: C) -> Self { + let buf = str_cow_to_bytes(name); BytesStart { - buf: Cow::Borrowed(content.as_bytes()), - name_len, + name_len: buf.len(), + buf, } } - /// Creates a new `BytesStart` from the given name. + /// Creates a new `BytesStart` from the given content (name + attributes). /// /// # Warning /// - /// `name` is not checked to be a valid name + /// `&content[..name_len]` must be a valid name, and the remainder of `content` + /// must be correctly-formed attributes. Neither are checked, it is possible + /// to generate invalid XML if `content` or `name_len` are incorrect. #[inline] - pub fn borrowed_name(name: &'a str) -> BytesStart<'a> { - Self::borrowed(name, name.len()) - } - - /// Creates a new `BytesStart` from the given content (name + attributes) - /// - /// Owns its contents. - #[inline] - pub fn owned>(content: C, name_len: usize) -> BytesStart<'static> { + pub fn from_content>>(content: C, name_len: usize) -> Self { BytesStart { - buf: Cow::Owned(content.into().into_bytes()), + buf: str_cow_to_bytes(content), name_len, } } - /// Creates a new `BytesStart` from the given name - /// - /// Owns its contents. - #[inline] - pub fn owned_name>(name: C) -> BytesStart<'static> { - let content = name.into().into_bytes(); - BytesStart { - name_len: content.len(), - buf: Cow::Owned(content), - } - } - /// Converts the event into an owned event. pub fn into_owned(self) -> BytesStart<'static> { BytesStart { @@ -255,7 +241,7 @@ impl<'a> BytesStart<'a> { /// /// # Warning /// - /// `name` is not checked to be a valid name + /// `name` must be a valid name. pub fn set_name(&mut self, name: &[u8]) -> &mut BytesStart<'a> { let bytes = self.buf.to_mut(); bytes.splice(..self.name_len, name.iter().cloned()); @@ -371,6 +357,53 @@ pub struct BytesDecl<'a> { } impl<'a> BytesDecl<'a> { + /// Constructs a new `XmlDecl` from the (mandatory) _version_ (should be `1.0` or `1.1`), + /// the optional _encoding_ (e.g., `UTF-8`) and the optional _standalone_ (`yes` or `no`) + /// attribute. + /// + /// Does not escape any of its inputs. Always uses double quotes to wrap the attribute values. + /// The caller is responsible for escaping attribute values. Shouldn't usually be relevant since + /// the double quote character is not allowed in any of the attribute values. + pub fn new( + version: &str, + encoding: Option<&str>, + standalone: Option<&str>, + ) -> BytesDecl<'static> { + // Compute length of the buffer based on supplied attributes + // ' encoding=""' => 12 + let encoding_attr_len = if let Some(xs) = encoding { + 12 + xs.len() + } else { + 0 + }; + // ' standalone=""' => 14 + let standalone_attr_len = if let Some(xs) = standalone { + 14 + xs.len() + } else { + 0 + }; + // 'xml version=""' => 14 + let mut buf = String::with_capacity(14 + encoding_attr_len + standalone_attr_len); + + buf.push_str("xml version=\""); + buf.push_str(version); + + if let Some(encoding_val) = encoding { + buf.push_str("\" encoding=\""); + buf.push_str(encoding_val); + } + + if let Some(standalone_val) = standalone { + buf.push_str("\" standalone=\""); + buf.push_str(standalone_val); + } + buf.push('"'); + + BytesDecl { + content: BytesStart::from_content(buf, 3), + } + } + /// Creates a `BytesDecl` from a `BytesStart` pub fn from_start(start: BytesStart<'a>) -> Self { Self { content: start } @@ -393,35 +426,35 @@ impl<'a> BytesDecl<'a> { /// use quick_xml::events::{BytesDecl, BytesStart}; /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" version='1.1'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); /// assert_eq!( /// decl.version().unwrap(), /// Cow::Borrowed(b"1.1".as_ref()) /// ); /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" version='1.0' version='1.1'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.0' version='1.1'", 0)); /// assert_eq!( /// decl.version().unwrap(), /// Cow::Borrowed(b"1.0".as_ref()) /// ); /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" encoding='utf-8'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8'", 0)); /// match decl.version() { /// Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding".to_string()), /// _ => assert!(false), /// } /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" encoding='utf-8' version='1.1'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8' version='1.1'", 0)); /// match decl.version() { /// Err(Error::XmlDeclWithoutVersion(Some(key))) => assert_eq!(key, "encoding".to_string()), /// _ => assert!(false), /// } /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed("", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content("", 0)); /// match decl.version() { /// Err(Error::XmlDeclWithoutVersion(None)) => {}, /// _ => assert!(false), @@ -461,18 +494,18 @@ impl<'a> BytesDecl<'a> { /// use quick_xml::events::{BytesDecl, BytesStart}; /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" version='1.1'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); /// assert!(decl.encoding().is_none()); /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" encoding='utf-8'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8'", 0)); /// match decl.encoding() { /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"utf-8"), /// _ => assert!(false), /// } /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" encoding='something_WRONG' encoding='utf-8'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='something_WRONG' encoding='utf-8'", 0)); /// match decl.encoding() { /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"something_WRONG"), /// _ => assert!(false), @@ -503,18 +536,18 @@ impl<'a> BytesDecl<'a> { /// use quick_xml::events::{BytesDecl, BytesStart}; /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" version='1.1'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); /// assert!(decl.standalone().is_none()); /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" standalone='yes'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" standalone='yes'", 0)); /// match decl.standalone() { /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"yes"), /// _ => assert!(false), /// } /// /// // - /// let decl = BytesDecl::from_start(BytesStart::borrowed(" standalone='something_WRONG' encoding='utf-8'", 0)); + /// let decl = BytesDecl::from_start(BytesStart::from_content(" standalone='something_WRONG' encoding='utf-8'", 0)); /// match decl.standalone() { /// Some(Ok(Cow::Borrowed(flag))) => assert_eq!(flag, b"something_WRONG"), /// _ => assert!(false), @@ -529,53 +562,6 @@ impl<'a> BytesDecl<'a> { .transpose() } - /// Constructs a new `XmlDecl` from the (mandatory) _version_ (should be `1.0` or `1.1`), - /// the optional _encoding_ (e.g., `UTF-8`) and the optional _standalone_ (`yes` or `no`) - /// attribute. - /// - /// Does not escape any of its inputs. Always uses double quotes to wrap the attribute values. - /// The caller is responsible for escaping attribute values. Shouldn't usually be relevant since - /// the double quote character is not allowed in any of the attribute values. - pub fn new( - version: &str, - encoding: Option<&str>, - standalone: Option<&str>, - ) -> BytesDecl<'static> { - // Compute length of the buffer based on supplied attributes - // ' encoding=""' => 12 - let encoding_attr_len = if let Some(xs) = encoding { - 12 + xs.len() - } else { - 0 - }; - // ' standalone=""' => 14 - let standalone_attr_len = if let Some(xs) = standalone { - 14 + xs.len() - } else { - 0 - }; - // 'xml version=""' => 14 - let mut buf = String::with_capacity(14 + encoding_attr_len + standalone_attr_len); - - buf.push_str("xml version=\""); - buf.push_str(version); - - if let Some(encoding_val) = encoding { - buf.push_str("\" encoding=\""); - buf.push_str(encoding_val); - } - - if let Some(standalone_val) = standalone { - buf.push_str("\" standalone=\""); - buf.push_str(standalone_val); - } - buf.push('"'); - - BytesDecl { - content: BytesStart::owned(buf, 3), - } - } - /// Gets the decoder struct #[cfg(feature = "encoding")] pub fn encoder(&self) -> Option<&'static Encoding> { @@ -623,20 +609,14 @@ impl<'a> BytesEnd<'a> { BytesEnd { name } } - /// Creates a new `BytesEnd` borrowing a slice - #[inline] - pub fn borrowed(name: &'a str) -> BytesEnd<'a> { - BytesEnd { - name: Cow::Borrowed(name.as_bytes()), - } - } - - /// Creates a new `BytesEnd` owning its name + /// Creates a new `BytesEnd` borrowing a slice. + /// + /// # Warning + /// + /// `name` must be a valid name. #[inline] - pub fn owned(name: String) -> BytesEnd<'static> { - BytesEnd { - name: Cow::Owned(name.into_bytes()), - } + pub fn new>>(name: C) -> Self { + Self::wrap(str_cow_to_bytes(name)) } /// Converts the event into an owned event. @@ -712,27 +692,15 @@ impl<'a> BytesText<'a> { /// Creates a new `BytesText` from an escaped string. #[inline] - pub fn from_escaped_str>>(content: C) -> Self { - Self::wrap( - match content.into() { - Cow::Owned(o) => Cow::Owned(o.into_bytes()), - Cow::Borrowed(b) => Cow::Borrowed(b.as_bytes()), - }, - Decoder::utf8(), - ) + pub fn from_escaped>>(content: C) -> Self { + Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) } /// Creates a new `BytesText` from a string. The string is expected not to /// be escaped. #[inline] - pub fn from_plain_str(content: &'a str) -> Self { - Self { - content: match escape(content) { - Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), - Cow::Owned(s) => Cow::Owned(s.into_bytes()), - }, - decoder: Decoder::utf8(), - } + pub fn new(content: &'a str) -> Self { + Self::from_escaped(escape(content)) } /// Ensures that all data is owned to extend the object's lifetime if @@ -853,10 +821,14 @@ impl<'a> BytesCData<'a> { } } - /// Creates a new `BytesCData` from a string + /// Creates a new `BytesCData` from a string. + /// + /// # Warning + /// + /// `content` must not contain the `]]>` sequence. #[inline] - pub fn from_str(content: &'a str) -> Self { - Self::wrap(content.as_bytes(), Decoder::utf8()) + pub fn new>>(content: C) -> Self { + Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) } /// Ensures that all data is owned to extend the object's lifetime if @@ -1102,6 +1074,14 @@ impl<'a> AsRef> for Event<'a> { //////////////////////////////////////////////////////////////////////////////////////////////////// +#[inline] +fn str_cow_to_bytes<'a, C: Into>>(content: C) -> Cow<'a, [u8]> { + match content.into() { + Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), + Cow::Owned(s) => Cow::Owned(s.into_bytes()), + } +} + #[cfg(test)] mod test { use super::*; @@ -1109,14 +1089,14 @@ mod test { #[test] fn bytestart_create() { - let b = BytesStart::owned_name("test"); + let b = BytesStart::new("test"); assert_eq!(b.len(), 4); assert_eq!(b.name(), QName(b"test")); } #[test] fn bytestart_set_name() { - let mut b = BytesStart::owned_name("test"); + let mut b = BytesStart::new("test"); assert_eq!(b.len(), 4); assert_eq!(b.name(), QName(b"test")); assert_eq!(b.attributes_raw(), b""); @@ -1130,7 +1110,7 @@ mod test { #[test] fn bytestart_clear_attributes() { - let mut b = BytesStart::owned_name("test"); + let mut b = BytesStart::new("test"); b.push_attribute(("x", "y\"z")); b.push_attribute(("x", "y\"z")); b.clear_attributes(); diff --git a/src/name.rs b/src/name.rs index ec1bdb50..ea304e02 100644 --- a/src/name.rs +++ b/src/name.rs @@ -574,11 +574,14 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns='default'", 0), &mut buffer); + resolver.push( + &BytesStart::from_content(" xmlns='default'", 0), + &mut buffer, + ); assert_eq!(buffer, b"default"); // Check that tags without namespaces does not change result - resolver.push(&BytesStart::borrowed("", 0), &mut buffer); + resolver.push(&BytesStart::from_content("", 0), &mut buffer); assert_eq!(buffer, b"default"); resolver.pop(&mut buffer); @@ -604,8 +607,8 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns='old'", 0), &mut buffer); - resolver.push(&BytesStart::borrowed(" xmlns='new'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns='new'", 0), &mut buffer); assert_eq!(buffer, b"oldnew"); assert_eq!( @@ -643,8 +646,8 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns='old'", 0), &mut buffer); - resolver.push(&BytesStart::borrowed(" xmlns=''", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns='old'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns=''", 0), &mut buffer); assert_eq!(buffer, b"old"); assert_eq!( @@ -684,11 +687,14 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns:p='default'", 0), &mut buffer); + resolver.push( + &BytesStart::from_content(" xmlns:p='default'", 0), + &mut buffer, + ); assert_eq!(buffer, b"pdefault"); // Check that tags without namespaces does not change result - resolver.push(&BytesStart::borrowed("", 0), &mut buffer); + resolver.push(&BytesStart::from_content("", 0), &mut buffer); assert_eq!(buffer, b"pdefault"); resolver.pop(&mut buffer); @@ -714,8 +720,8 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns:p='old'", 0), &mut buffer); - resolver.push(&BytesStart::borrowed(" xmlns:p='new'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns:p='new'", 0), &mut buffer); assert_eq!(buffer, b"poldpnew"); assert_eq!( @@ -753,8 +759,8 @@ mod namespaces { let mut resolver = NamespaceResolver::default(); let mut buffer = Vec::new(); - resolver.push(&BytesStart::borrowed(" xmlns:p='old'", 0), &mut buffer); - resolver.push(&BytesStart::borrowed(" xmlns:p=''", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns:p='old'", 0), &mut buffer); + resolver.push(&BytesStart::from_content(" xmlns:p=''", 0), &mut buffer); assert_eq!(buffer, b"poldp"); assert_eq!( diff --git a/src/reader/buffered_reader.rs b/src/reader/buffered_reader.rs index 384f71cd..c86f5ace 100644 --- a/src/reader/buffered_reader.rs +++ b/src/reader/buffered_reader.rs @@ -124,7 +124,7 @@ impl Reader { /// reader.trim_text(true); /// let mut buf = Vec::new(); /// - /// let start = BytesStart::borrowed_name("outer"); + /// let start = BytesStart::new("outer"); /// let end = start.to_end().into_owned(); /// /// // First, we read a start event... diff --git a/src/reader/mod.rs b/src/reader/mod.rs index 8fd778b2..e4c8f342 100644 --- a/src/reader/mod.rs +++ b/src/reader/mod.rs @@ -1844,7 +1844,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::StartText(BytesText::from_escaped_str("bom").into()) + Event::StartText(BytesText::from_escaped("bom").into()) ); } @@ -1854,7 +1854,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Decl(BytesDecl::from_start(BytesStart::borrowed("xml ", 3))) + Event::Decl(BytesDecl::from_start(BytesStart::from_content("xml ", 3))) ); } @@ -1864,7 +1864,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::DocType(BytesText::from_escaped_str("x")) + Event::DocType(BytesText::from_escaped("x")) ); } @@ -1874,7 +1874,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::PI(BytesText::from_escaped_str("xml-stylesheet")) + Event::PI(BytesText::from_escaped("xml-stylesheet")) ); } @@ -1884,7 +1884,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Start(BytesStart::borrowed_name("tag")) + Event::Start(BytesStart::new("tag")) ); } @@ -1897,7 +1897,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::End(BytesEnd::borrowed("tag")) + Event::End(BytesEnd::new("tag")) ); } @@ -1907,7 +1907,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Empty(BytesStart::borrowed_name("tag")) + Event::Empty(BytesStart::new("tag")) ); } @@ -1918,12 +1918,12 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Empty(BytesStart::borrowed_name("tag")) + Event::Empty(BytesStart::new("tag")) ); assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Text(BytesText::from_escaped_str("text")) + Event::Text(BytesText::from_escaped("text")) ); } @@ -1933,7 +1933,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::CData(BytesCData::from_str("")) + Event::CData(BytesCData::new("")) ); } @@ -1943,7 +1943,7 @@ mod test { assert_eq!( reader.read_event_impl($buf).unwrap(), - Event::Comment(BytesText::from_escaped_str("")) + Event::Comment(BytesText::from_escaped("")) ); } diff --git a/src/reader/ns_reader.rs b/src/reader/ns_reader.rs index 7a02492d..868e88f4 100644 --- a/src/reader/ns_reader.rs +++ b/src/reader/ns_reader.rs @@ -472,7 +472,7 @@ impl NsReader { /// let mut buf = Vec::new(); /// /// let ns = Namespace(b"namespace 1"); - /// let start = BytesStart::borrowed(r#"outer xmlns="namespace 1""#, 5); + /// let start = BytesStart::from_content(r#"outer xmlns="namespace 1""#, 5); /// let end = start.to_end().into_owned(); /// /// // First, we read a start event... @@ -693,7 +693,7 @@ impl<'i> NsReader<&'i [u8]> { /// reader.trim_text(true); /// /// let ns = Namespace(b"namespace 1"); - /// let start = BytesStart::borrowed(r#"outer xmlns="namespace 1""#, 5); + /// let start = BytesStart::from_content(r#"outer xmlns="namespace 1""#, 5); /// let end = start.to_end().into_owned(); /// /// // First, we read a start event... diff --git a/src/reader/slice_reader.rs b/src/reader/slice_reader.rs index 5a968f2d..0a71f050 100644 --- a/src/reader/slice_reader.rs +++ b/src/reader/slice_reader.rs @@ -93,7 +93,7 @@ impl<'a> Reader<&'a [u8]> { /// "#); /// reader.trim_text(true); /// - /// let start = BytesStart::borrowed_name("outer"); + /// let start = BytesStart::new("outer"); /// let end = start.to_end().into_owned(); /// /// // First, we read a start event... diff --git a/src/se/mod.rs b/src/se/mod.rs index 92d965ea..b05c9881 100644 --- a/src/se/mod.rs +++ b/src/se/mod.rs @@ -102,9 +102,9 @@ impl<'r, W: Write> Serializer<'r, W> { ) -> Result<(), DeError> { let value = value.to_string(); let event = if escaped { - BytesText::from_escaped_str(&value) + BytesText::from_escaped(&value) } else { - BytesText::from_plain_str(&value) + BytesText::new(&value) }; self.writer.write_event(Event::Text(event))?; Ok(()) @@ -113,7 +113,7 @@ impl<'r, W: Write> Serializer<'r, W> { /// Writes self-closed tag `` into inner writer fn write_self_closed(&mut self, tag_name: &str) -> Result<(), DeError> { self.writer - .write_event(Event::Empty(BytesStart::borrowed_name(tag_name)))?; + .write_event(Event::Empty(BytesStart::new(tag_name)))?; Ok(()) } @@ -124,10 +124,10 @@ impl<'r, W: Write> Serializer<'r, W> { value: &T, ) -> Result<(), DeError> { self.writer - .write_event(Event::Start(BytesStart::borrowed_name(tag_name)))?; + .write_event(Event::Start(BytesStart::new(tag_name)))?; value.serialize(&mut *self)?; self.writer - .write_event(Event::End(BytesEnd::borrowed(tag_name)))?; + .write_event(Event::End(BytesEnd::new(tag_name)))?; Ok(()) } } @@ -306,7 +306,7 @@ impl<'r, 'w, W: Write> ser::Serializer for &'w mut Serializer<'r, W> { if let Some(tag) = self.root_tag { // TODO: Write self-closed tag if map is empty self.writer - .write_event(Event::Start(BytesStart::borrowed_name(tag)))?; + .write_event(Event::Start(BytesStart::new(tag)))?; } Ok(Map::new(self)) } diff --git a/src/se/var.rs b/src/se/var.rs index 5990d709..c8e062eb 100644 --- a/src/se/var.rs +++ b/src/se/var.rs @@ -54,7 +54,7 @@ where if let Some(tag) = self.parent.root_tag { self.parent .writer - .write_event(Event::End(BytesEnd::borrowed(tag)))?; + .write_event(Event::End(BytesEnd::new(tag)))?; } Ok(()) } @@ -102,7 +102,7 @@ where pub fn new(parent: &'w mut Serializer<'r, W>, name: &'r str) -> Self { Struct { parent, - attrs: BytesStart::borrowed_name(name), + attrs: BytesStart::new(name), children: Vec::new(), buffer: Vec::new(), } diff --git a/src/writer.rs b/src/writer.rs index 12250fbd..e42c231d 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -26,7 +26,7 @@ use std::io::Write; /// /// // crates a new element ... alternatively we could reuse `e` by calling /// // `e.into_owned()` -/// let mut elem = BytesStart::owned_name("my_elem"); +/// let mut elem = BytesStart::new("my_elem"); /// /// // collect existing attributes /// elem.extend_attributes(e.attributes().map(|attr| attr.unwrap())); @@ -38,7 +38,7 @@ use std::io::Write; /// assert!(writer.write_event(Event::Start(elem)).is_ok()); /// }, /// Ok(Event::End(e)) if e.name().as_ref() == b"this_tag" => { -/// assert!(writer.write_event(Event::End(BytesEnd::borrowed("my_elem"))).is_ok()); +/// assert!(writer.write_event(Event::End(BytesEnd::new("my_elem"))).is_ok()); /// }, /// Ok(Event::Eof) => break, /// // we can either move or borrow the event to write, depending on your use-case @@ -193,7 +193,7 @@ impl Writer { /// // writes with some text inside /// writer.create_element("tag") /// .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()) // or add attributes from an iterator - /// .write_text_content(BytesText::from_plain_str("with some text inside"))?; + /// .write_text_content(BytesText::new("with some text inside"))?; /// /// // writes appleorange /// writer.create_element("tag") @@ -203,7 +203,7 @@ impl Writer { /// writer /// .create_element("fruit") /// .with_attribute(("quantity", quant.to_string().as_str())) - /// .write_text_content(BytesText::from_plain_str(item))?; + /// .write_text_content(BytesText::new(item))?; /// } /// Ok(()) /// })?; @@ -217,7 +217,7 @@ impl Writer { { ElementWriter { writer: self, - start_tag: BytesStart::borrowed_name(name.as_ref()), + start_tag: BytesStart::new(name.as_ref()), } } } @@ -347,7 +347,7 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let tag = BytesStart::borrowed_name("self-closed") + let tag = BytesStart::new("self-closed") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); writer .write_event(Event::Empty(tag)) @@ -364,7 +364,7 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let start = BytesStart::borrowed_name("paired") + let start = BytesStart::new("paired") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); let end = start.to_end(); writer @@ -386,10 +386,10 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let start = BytesStart::borrowed_name("paired") + let start = BytesStart::new("paired") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); let end = start.to_end(); - let inner = BytesStart::borrowed_name("inner"); + let inner = BytesStart::new("inner"); writer .write_event(Event::Start(start.clone())) @@ -414,10 +414,10 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let start = BytesStart::borrowed_name("paired") + let start = BytesStart::new("paired") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); let end = start.to_end(); - let text = BytesText::from_plain_str("text"); + let text = BytesText::new("text"); writer .write_event(Event::Start(start.clone())) @@ -440,11 +440,11 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let start = BytesStart::borrowed_name("paired") + let start = BytesStart::new("paired") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); let end = start.to_end(); - let text = BytesText::from_plain_str("text"); - let inner = BytesStart::borrowed_name("inner"); + let text = BytesText::new("text"); + let inner = BytesStart::new("inner"); writer .write_event(Event::Start(start.clone())) @@ -471,10 +471,10 @@ mod indentation { let mut buffer = Vec::new(); let mut writer = Writer::new_with_indent(&mut buffer, b' ', 4); - let start = BytesStart::borrowed_name("paired") + let start = BytesStart::new("paired") .with_attributes(vec![("attr1", "value1"), ("attr2", "value2")].into_iter()); let end = start.to_end(); - let inner = BytesStart::borrowed_name("inner"); + let inner = BytesStart::new("inner"); writer .write_event(Event::Start(start.clone())) @@ -528,7 +528,7 @@ mod indentation { .create_element("paired") .with_attribute(("attr1", "value1")) .with_attribute(("attr2", "value2")) - .write_text_content(BytesText::from_plain_str("text")) + .write_text_content(BytesText::new("text")) .expect("failure"); assert_eq!( @@ -552,7 +552,7 @@ mod indentation { writer .create_element("fruit") .with_attribute(("quantity", quant.to_string().as_str())) - .write_text_content(BytesText::from_plain_str(item))?; + .write_text_content(BytesText::new(item))?; } writer .create_element("inner") diff --git a/tests/unit_tests.rs b/tests/unit_tests.rs index fdaad2d3..80407736 100644 --- a/tests/unit_tests.rs +++ b/tests/unit_tests.rs @@ -319,12 +319,12 @@ fn test_write_attrs() -> Result<()> { Start(elem) => { let mut attrs = elem.attributes().collect::>>()?; attrs.extend_from_slice(&[("a", "b").into(), ("c", "d").into()]); - let mut elem = BytesStart::owned_name("copy"); + let mut elem = BytesStart::new("copy"); elem.extend_attributes(attrs); elem.push_attribute(("x", "y\"z")); Start(elem) } - End(_) => End(BytesEnd::borrowed("copy")), + End(_) => End(BytesEnd::new("copy")), e => e, }; assert!(writer.write_event(event).is_ok()); @@ -596,9 +596,7 @@ fn test_read_write_roundtrip_escape_text() -> Result<()> { Eof => break, Text(e) => { let t = e.unescape().unwrap(); - assert!(writer - .write_event(Text(BytesText::from_plain_str(&t))) - .is_ok()); + assert!(writer.write_event(Text(BytesText::new(&t))).is_ok()); } e => assert!(writer.write_event(e).is_ok()), }