diff options
Diffstat (limited to '')
-rw-r--r-- | askama_shared/src/escaping.rs | 50 | ||||
-rw-r--r-- | askama_shared/src/filters/mod.rs | 46 | ||||
-rw-r--r-- | askama_shared/src/lib.rs | 1 |
3 files changed, 54 insertions, 43 deletions
diff --git a/askama_shared/src/escaping.rs b/askama_shared/src/escaping.rs new file mode 100644 index 0000000..54f58e4 --- /dev/null +++ b/askama_shared/src/escaping.rs @@ -0,0 +1,50 @@ +fn escapable(b: &u8) -> bool { + *b == b'<' || *b == b'>' || *b == b'&' +} + +pub fn escape(s: String) -> String { + let mut found = Vec::new(); + for (i, b) in s.as_bytes().iter().enumerate() { + if escapable(b) { + found.push(i); + } + } + if found.is_empty() { + return s; + } + + let bytes = s.as_bytes(); + let max_len = bytes.len() + found.len() * 3; + let mut res = Vec::<u8>::with_capacity(max_len); + let mut start = 0; + for idx in &found { + if start < *idx { + res.extend(&bytes[start..*idx]); + } + start = *idx + 1; + match bytes[*idx] { + b'<' => { res.extend(b"<"); }, + b'>' => { res.extend(b">"); }, + b'&' => { res.extend(b"&"); }, + _ => panic!("incorrect indexing"), + } + } + if start < bytes.len() - 1 { + res.extend(&bytes[start..]); + } + + String::from_utf8(res).unwrap() +} + + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_escape() { + assert_eq!(escape("".to_string()), ""); + assert_eq!(escape("<&>".to_string()), "<&>"); + assert_eq!(escape("bla&".to_string()), "bla&"); + assert_eq!(escape("<foo".to_string()), "<foo"); + } +} diff --git a/askama_shared/src/filters/mod.rs b/askama_shared/src/filters/mod.rs index 1f5fa42..e6a5858 100644 --- a/askama_shared/src/filters/mod.rs +++ b/askama_shared/src/filters/mod.rs @@ -13,6 +13,7 @@ pub use self::json::json; use std::fmt; +use escaping; use super::Result; @@ -33,44 +34,10 @@ pub const BUILT_IN_FILTERS: [&str; 9] = [ ]; -fn escapable(b: &u8) -> bool { - *b == b'<' || *b == b'>' || *b == b'&' -} - /// Escapes `&`, `<` and `>` in strings pub fn escape(s: &fmt::Display) -> Result<String> { let s = format!("{}", s); - let mut found = Vec::new(); - for (i, b) in s.as_bytes().iter().enumerate() { - if escapable(b) { - found.push(i); - } - } - if found.is_empty() { - return Ok(s); - } - - let bytes = s.as_bytes(); - let max_len = bytes.len() + found.len() * 3; - let mut res = Vec::<u8>::with_capacity(max_len); - let mut start = 0; - for idx in &found { - if start < *idx { - res.extend(&bytes[start..*idx]); - } - start = *idx + 1; - match bytes[*idx] { - b'<' => { res.extend(b"<"); }, - b'>' => { res.extend(b">"); }, - b'&' => { res.extend(b"&"); }, - _ => panic!("incorrect indexing"), - } - } - if start < bytes.len() - 1 { - res.extend(&bytes[start..]); - } - - Ok(String::from_utf8(res).unwrap()) + Ok(escaping::escape(s)) } /// Alias for the `escape()` filter @@ -135,18 +102,11 @@ pub fn join<T, I, S>(input: I, separator: S) -> Result<String> Ok(rv) } + #[cfg(test)] mod tests { use super::*; #[test] - fn test_escape() { - assert_eq!(escape(&"").unwrap(), ""); - assert_eq!(escape(&"<&>").unwrap(), "<&>"); - assert_eq!(escape(&"bla&").unwrap(), "bla&"); - assert_eq!(escape(&"<foo").unwrap(), "<foo"); - } - - #[test] fn test_lower() { assert_eq!(lower(&"Foo").unwrap(), "foo"); assert_eq!(lower(&"FOO").unwrap(), "foo"); diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index 301ca13..35e779c 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -16,6 +16,7 @@ pub mod path; pub use parser::parse; pub use generator::generate; +mod escaping; mod generator; mod parser; |