1#![no_std]
16#![cfg_attr(feature = "docsrs", feature(doc_cfg))]
17#![forbid(unsafe_code)]
18#![allow(unused_attributes)]
19#![warn(absolute_paths_not_starting_with_crate)]
20#![warn(elided_lifetimes_in_paths)]
21#![warn(explicit_outlives_requirements)]
22#![warn(meta_variable_misuse)]
23#![warn(missing_copy_implementations)]
24#![warn(missing_debug_implementations)]
25#![warn(missing_docs)]
26#![warn(non_ascii_idents)]
27#![warn(noop_method_call)]
28#![warn(single_use_lifetimes)]
29#![warn(trivial_casts)]
30#![warn(unreachable_pub)]
31#![warn(unused_crate_dependencies)]
32#![warn(unused_extern_crates)]
33#![warn(unused_lifetimes)]
34#![warn(unused_results)]
35#![no_implicit_prelude]
36
37#![cfg_attr(feature = "docsrs", doc = ::document_features::document_features!())]
47
48#[doc(hidden)]
49pub mod details;
50mod raw_marker;
51
52use details::alloc;
53use details::std::fmt::{self, Arguments, Write as _};
54use details::std::prelude::v1::*;
55use details::std::write;
56pub use raw_marker::{EscapeTag, RawMarker, RawTag};
57
58#[doc(hidden)]
59pub trait WriteAny {
60 fn write_fmt(&mut self, fmt: Arguments<'_>) -> fmt::Result;
61}
62
63pub trait RenderInto {
67 #[doc(hidden)]
68 fn render_into(&self, output: impl WriteAny) -> fmt::Result;
69
70 #[inline]
72 fn render_fmt(&self, output: impl fmt::Write) -> fmt::Result {
73 self.render_into(details::WriteFmt(output))
74 }
75
76 #[cfg(feature = "alloc")]
78 #[cfg_attr(feature = "docsrs", doc(cfg(any(feature = "alloc", feature = "std"))))]
79 #[inline]
80 fn render_io(&self, output: impl alloc::io::Write) -> fmt::Result {
81 self.render_into(details::WriteIo(output))
82 }
83
84 #[cfg(feature = "alloc")]
86 #[cfg_attr(feature = "docsrs", doc(cfg(any(feature = "alloc", feature = "std"))))]
87 fn render_string(&self) -> Result<alloc::string::String, fmt::Error> {
88 let mut result = String::new();
89 self.render_fmt(&mut result)?;
90 Ok(result)
91 }
92
93 #[cfg(feature = "alloc")]
95 #[cfg_attr(feature = "docsrs", doc(cfg(any(feature = "alloc", feature = "std"))))]
96 fn render_bytes(&self) -> Result<alloc::vec::Vec<u8>, fmt::Error> {
97 let mut result = Vec::new();
98 self.render_io(&mut result)?;
99 Ok(result)
100 }
101}
102
103pub struct XmlEscape<T: ?Sized>(pub T);
108
109impl<T: ?Sized + fmt::Display> fmt::Display for XmlEscape<T> {
110 #[inline]
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(XmlEscapeWriter(f), "{}", &self.0)
113 }
114}
115
116impl<T: ?Sized + fmt::Debug> fmt::Debug for XmlEscape<T> {
117 #[inline]
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(XmlEscapeWriter(f), "{:?}", &self.0)
120 }
121}
122
123struct XmlEscapeWriter<'a, 'b>(&'a mut fmt::Formatter<'b>);
124
125impl fmt::Write for XmlEscapeWriter<'_, '_> {
126 fn write_str(&mut self, mut s: &str) -> fmt::Result {
127 loop {
128 let mut done = true;
129 for (i, c) in s.as_bytes().iter().enumerate() {
130 let c = match c {
131 b'"' => """,
132 b'&' => "&",
133 b'\'' => "'",
134 b'<' => "<",
135 b'>' => ">",
136 _ => continue,
137 };
138 write!(self.0, "{}{}", &s[..i], c)?;
139 s = &s[i + 1..];
140 done = false;
141 break;
142 }
143 if done {
144 if !s.is_empty() {
145 self.0.write_str(s)?;
146 }
147 break Ok(());
148 }
149 }
150 }
151
152 fn write_char(&mut self, c: char) -> fmt::Result {
153 self.0.write_str(match c {
154 '"' => """,
155 '&' => "&",
156 '\'' => "'",
157 '<' => "<",
158 '>' => ">",
159 c => return self.0.write_char(c),
160 })
161 }
162}