/// True if `c` is considered a whitespace according to Rust language definition. /// See [Rust language reference](https://doc.rust-lang.org/reference/whitespace.html) /// for definitions of these classes. pub fn is_whitespace(c: char) -> bool { // This is Pattern_White_Space. // // Note that this set is stable (ie, it doesn't change with different // Unicode versions), so it's ok to just hard-code the values. matches!( c, // Usual ASCII suspects '\u{0009}' // \t | '\u{000A}' // \n | '\u{000B}' // vertical tab | '\u{000C}' // form feed | '\u{000D}' // \r | '\u{0020}' // space // NEXT LINE from latin1 | '\u{0085}' // Bidi markers | '\u{200E}' // LEFT-TO-RIGHT MARK | '\u{200F}' // RIGHT-TO-LEFT MARK // Dedicated whitespace characters from Unicode | '\u{2028}' // LINE SEPARATOR | '\u{2029}' // PARAGRAPH SEPARATOR ) } /// True if `c` is valid as a first character of an identifier. /// See [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html) for /// a formal definition of valid identifier name. pub fn is_id_start(c: char) -> bool { // This is XID_Start OR '_' (which formally is not a XID_Start). c == '_' || unicode_xid::UnicodeXID::is_xid_start(c) } /// True if `c` is valid as a non-first character of an identifier. /// See [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html) for /// a formal definition of valid identifier name. pub fn is_id_continue(c: char) -> bool { unicode_xid::UnicodeXID::is_xid_continue(c) } /// The passed string is lexically an identifier. pub fn is_ident(string: &str) -> bool { let mut chars = string.chars(); if let Some(start) = chars.next() { is_id_start(start) && chars.all(is_id_continue) } else { false } } pub fn is_digit(ch: char) -> bool { ('0'..='9').contains(&ch) } pub fn is_bin_digit(ch: char) -> bool { ch == '0' || ch == '1' } pub fn is_nonzero_digit(ch: char) -> bool { ('1'..='9').contains(&ch) } pub fn is_oct_digit(ch: char) -> bool { ('0'..='7').contains(&ch) } pub fn is_hex_digit(ch: char) -> bool { ('0'..='9').contains(&ch) || ('a'..='f').contains(&ch) || ('A'..='F').contains(&ch) } /// Trait for only yielding the next item in the Iterator if it tests true for some predicate pub trait NextIf: Iterator + Clone { /// Yield next item if `pred` returns `true`. /// If `pred` returns `false` the Iterator is not advanced. #[must_use] fn next_if(&mut self, pred: F) -> Option where F: FnOnce(&Self::Item) -> bool, { let old = self.clone(); match self.next() { Some(item) => { if pred(&item) { Some(item) } else { *self = old; None } } None => None, } } /// Yield next item if `pred` returns `Some(T)`. /// If `pred` returns `None` the Iterator is not advanced. #[must_use] fn next_if_map(&mut self, pred: F) -> Option where F: FnOnce(Self::Item) -> Option, { let old = self.clone(); match self.next() { Some(item) => match pred(item) { None => { *self = old; None } some => some, }, None => None, } } } impl NextIf for T where T: Iterator + Clone {} pub trait FallibleParse: Iterator + Clone { /// consumes items from `self` if and only if `map` yields `Some`. #[must_use] fn try_parse(&mut self, map: F) -> Option where F: FnOnce(&mut Self) -> Option, { // clone iterator and keep around let old = self.clone(); match map(self) { Some(result) => Some(result), None => { // the map function failed, restore iterator and yield None. *self = old; None } } } #[must_use] fn try_parse_result(&mut self, map: F) -> Result where F: FnOnce(&mut Self) -> Result, { // clone iterator and keep around let old = self.clone(); match map(self) { Ok(result) => Ok(result), Err(e) => { // the map function failed, restore iterator and yield None. *self = old; Err(e) } } } } impl FallibleParse for T where T: Iterator + Clone {} #[macro_export] macro_rules! variant { ($value:expr => $pattern:pat) => { let $pattern = $value else { unreachable!() }; }; ($pattern:pat = $value:expr) => { let $pattern = $value else { unreachable!() }; }; } pub fn from_lo_hi_dwords(lo: u32, hi: u32) -> u64 { lo as u64 | (hi as u64) << 32 } pub fn into_lo_hi_dwords(qword: u64) -> (u32, u32) { (qword as u32, (qword >> 32) as u32) }