parent
ce1c198552
commit
f78121f9d3
@ -1,156 +0,0 @@ |
|||||||
use crate::utils::StaticSliceMap; |
|
||||||
use std::borrow::Cow; |
|
||||||
use std::char; |
|
||||||
use std::str::Chars; |
|
||||||
|
|
||||||
pub fn unescape_unicode_codepoints(input: &str) -> Cow<'_, str> { |
|
||||||
if needs_unescape_unicode_codepoints(input) { |
|
||||||
UnescapeUnicodeCharIterator::new(input).collect() |
|
||||||
} else { |
|
||||||
input.into() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fn needs_unescape_unicode_codepoints(input: &str) -> bool { |
|
||||||
let bytes = input.as_bytes(); |
|
||||||
for i in 1..bytes.len() { |
|
||||||
if (bytes[i] == b'u' || bytes[i] == b'U') && bytes[i - 1] == b'\\' { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
false |
|
||||||
} |
|
||||||
|
|
||||||
struct UnescapeUnicodeCharIterator<'a> { |
|
||||||
iter: Chars<'a>, |
|
||||||
buffer: String, |
|
||||||
} |
|
||||||
|
|
||||||
impl<'a> UnescapeUnicodeCharIterator<'a> { |
|
||||||
fn new(string: &'a str) -> Self { |
|
||||||
Self { |
|
||||||
iter: string.chars(), |
|
||||||
buffer: String::with_capacity(9), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl<'a> Iterator for UnescapeUnicodeCharIterator<'a> { |
|
||||||
type Item = char; |
|
||||||
|
|
||||||
fn next(&mut self) -> Option<char> { |
|
||||||
if !self.buffer.is_empty() { |
|
||||||
return Some(self.buffer.remove(0)); |
|
||||||
} |
|
||||||
match self.iter.next()? { |
|
||||||
'\\' => match self.iter.next() { |
|
||||||
Some('u') => { |
|
||||||
self.buffer.push('u'); |
|
||||||
for _ in 0..4 { |
|
||||||
if let Some(c) = self.iter.next() { |
|
||||||
self.buffer.push(c); |
|
||||||
} else { |
|
||||||
return Some('\\'); |
|
||||||
} |
|
||||||
} |
|
||||||
if let Some(c) = u32::from_str_radix(&self.buffer[1..5], 16) |
|
||||||
.ok() |
|
||||||
.and_then(char::from_u32) |
|
||||||
{ |
|
||||||
self.buffer.clear(); |
|
||||||
Some(c) |
|
||||||
} else { |
|
||||||
Some('\\') |
|
||||||
} |
|
||||||
} |
|
||||||
Some('U') => { |
|
||||||
self.buffer.push('U'); |
|
||||||
for _ in 0..8 { |
|
||||||
if let Some(c) = self.iter.next() { |
|
||||||
self.buffer.push(c); |
|
||||||
} else { |
|
||||||
return Some('\\'); |
|
||||||
} |
|
||||||
} |
|
||||||
if let Some(c) = u32::from_str_radix(&self.buffer[1..9], 16) |
|
||||||
.ok() |
|
||||||
.and_then(char::from_u32) |
|
||||||
{ |
|
||||||
self.buffer.clear(); |
|
||||||
Some(c) |
|
||||||
} else { |
|
||||||
Some('\\') |
|
||||||
} |
|
||||||
} |
|
||||||
Some(c) => { |
|
||||||
self.buffer.push(c); |
|
||||||
Some('\\') |
|
||||||
} |
|
||||||
None => Some('\\'), |
|
||||||
}, |
|
||||||
c => Some(c), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pub fn unescape_characters<'a>( |
|
||||||
input: &'a str, |
|
||||||
characters: &'static [u8], |
|
||||||
replacement: &'static StaticSliceMap<char, char>, |
|
||||||
) -> Cow<'a, str> { |
|
||||||
if needs_unescape_characters(input, characters) { |
|
||||||
UnescapeCharsIterator::new(input, replacement).collect() |
|
||||||
} else { |
|
||||||
input.into() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fn needs_unescape_characters(input: &str, characters: &[u8]) -> bool { |
|
||||||
let bytes = input.as_bytes(); |
|
||||||
for i in 1..bytes.len() { |
|
||||||
if bytes[i - 1] == b'\\' && characters.contains(&bytes[i]) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
false |
|
||||||
} |
|
||||||
|
|
||||||
struct UnescapeCharsIterator<'a> { |
|
||||||
iter: Chars<'a>, |
|
||||||
buffer: Option<char>, |
|
||||||
replacement: &'static StaticSliceMap<char, char>, |
|
||||||
} |
|
||||||
|
|
||||||
impl<'a> UnescapeCharsIterator<'a> { |
|
||||||
fn new(string: &'a str, replacement: &'static StaticSliceMap<char, char>) -> Self { |
|
||||||
Self { |
|
||||||
iter: string.chars(), |
|
||||||
buffer: None, |
|
||||||
replacement, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl<'a> Iterator for UnescapeCharsIterator<'a> { |
|
||||||
type Item = char; |
|
||||||
|
|
||||||
fn next(&mut self) -> Option<char> { |
|
||||||
if let Some(ch) = self.buffer { |
|
||||||
self.buffer = None; |
|
||||||
return Some(ch); |
|
||||||
} |
|
||||||
match self.iter.next()? { |
|
||||||
'\\' => match self.iter.next() { |
|
||||||
Some(ch) => match self.replacement.get(ch) { |
|
||||||
Some(replace) => Some(replace), |
|
||||||
None => { |
|
||||||
self.buffer = Some(ch); |
|
||||||
Some('\\') |
|
||||||
} |
|
||||||
}, |
|
||||||
None => Some('\\'), |
|
||||||
}, |
|
||||||
c => Some(c), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,129 +0,0 @@ |
|||||||
use failure::Backtrace; |
|
||||||
use failure::Fail; |
|
||||||
use std::sync::PoisonError; |
|
||||||
|
|
||||||
pub trait Escaper { |
|
||||||
fn escape(&self) -> String; |
|
||||||
} |
|
||||||
|
|
||||||
impl Escaper for str { |
|
||||||
fn escape(&self) -> String { |
|
||||||
self.chars().flat_map(EscapeRDF::new).collect() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/// Customized version of EscapeDefault of the Rust standard library
|
|
||||||
struct EscapeRDF { |
|
||||||
state: EscapeRdfState, |
|
||||||
} |
|
||||||
|
|
||||||
enum EscapeRdfState { |
|
||||||
Done, |
|
||||||
Char(char), |
|
||||||
Backslash(char), |
|
||||||
} |
|
||||||
|
|
||||||
impl EscapeRDF { |
|
||||||
fn new(c: char) -> Self { |
|
||||||
Self { |
|
||||||
state: match c { |
|
||||||
'\t' => EscapeRdfState::Backslash('t'), |
|
||||||
'\u{08}' => EscapeRdfState::Backslash('b'), |
|
||||||
'\n' => EscapeRdfState::Backslash('n'), |
|
||||||
'\r' => EscapeRdfState::Backslash('r'), |
|
||||||
'\u{0C}' => EscapeRdfState::Backslash('f'), |
|
||||||
'\\' | '\'' | '"' => EscapeRdfState::Backslash(c), |
|
||||||
c => EscapeRdfState::Char(c), |
|
||||||
}, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl Iterator for EscapeRDF { |
|
||||||
type Item = char; |
|
||||||
|
|
||||||
fn next(&mut self) -> Option<char> { |
|
||||||
match self.state { |
|
||||||
EscapeRdfState::Backslash(c) => { |
|
||||||
self.state = EscapeRdfState::Char(c); |
|
||||||
Some('\\') |
|
||||||
} |
|
||||||
EscapeRdfState::Char(c) => { |
|
||||||
self.state = EscapeRdfState::Done; |
|
||||||
Some(c) |
|
||||||
} |
|
||||||
EscapeRdfState::Done => None, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) { |
|
||||||
let n = self.len(); |
|
||||||
(n, Some(n)) |
|
||||||
} |
|
||||||
|
|
||||||
fn count(self) -> usize { |
|
||||||
self.len() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl ExactSizeIterator for EscapeRDF { |
|
||||||
fn len(&self) -> usize { |
|
||||||
match self.state { |
|
||||||
EscapeRdfState::Done => 0, |
|
||||||
EscapeRdfState::Char(_) => 1, |
|
||||||
EscapeRdfState::Backslash(_) => 2, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#[test] |
|
||||||
fn test_escaper() { |
|
||||||
assert_eq!("foo", "foo".escape()); |
|
||||||
assert_eq!( |
|
||||||
"John said: \\\"Hello World!\\\"", |
|
||||||
"John said: \"Hello World!\"".escape() |
|
||||||
); |
|
||||||
assert_eq!( |
|
||||||
"John said: \\\"Hello World!\\\\\\\"", |
|
||||||
"John said: \"Hello World!\\\"".escape() |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
pub struct StaticSliceMap<K: 'static + Copy + Eq, V: 'static + Copy> { |
|
||||||
keys: &'static [K], |
|
||||||
values: &'static [V], |
|
||||||
} |
|
||||||
|
|
||||||
impl<K: 'static + Copy + Eq, V: 'static + Copy> StaticSliceMap<K, V> { |
|
||||||
pub fn new(keys: &'static [K], values: &'static [V]) -> Self { |
|
||||||
assert_eq!( |
|
||||||
keys.len(), |
|
||||||
values.len(), |
|
||||||
"keys and values slices of StaticSliceMap should have the same size" |
|
||||||
); |
|
||||||
Self { keys, values } |
|
||||||
} |
|
||||||
|
|
||||||
pub fn get(&self, key: K) -> Option<V> { |
|
||||||
for i in 0..self.keys.len() { |
|
||||||
if self.keys[i] == key { |
|
||||||
return Some(self.values[i]); |
|
||||||
} |
|
||||||
} |
|
||||||
None |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#[derive(Debug, Fail)] |
|
||||||
#[fail(display = "Mutex Mutex was poisoned")] |
|
||||||
pub struct MutexPoisonError { |
|
||||||
backtrace: Backtrace, |
|
||||||
} |
|
||||||
|
|
||||||
impl<T> From<PoisonError<T>> for MutexPoisonError { |
|
||||||
fn from(_: PoisonError<T>) -> Self { |
|
||||||
Self { |
|
||||||
backtrace: Backtrace::new(), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue