blob: 85a27ba7786729aa96d8bde37d5e34545dce1817 [file] [log] [blame]
macro_rules! impl_partial_eq {
($lhs:ty, $rhs:ty) => {
impl<'a, 'b> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
let other: &[u8] = other.as_ref();
PartialEq::eq(self.as_bytes(), other)
}
}
impl<'a, 'b> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
let this: &[u8] = self.as_ref();
PartialEq::eq(this, other.as_bytes())
}
}
};
}
#[cfg(feature = "std")]
macro_rules! impl_partial_eq_cow {
($lhs:ty, $rhs:ty) => {
impl<'a, 'b> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool {
let other: &[u8] = (&**other).as_ref();
PartialEq::eq(self.as_bytes(), other)
}
}
impl<'a, 'b> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool {
let this: &[u8] = (&**other).as_ref();
PartialEq::eq(this, self.as_bytes())
}
}
};
}
macro_rules! impl_partial_ord {
($lhs:ty, $rhs:ty) => {
impl<'a, 'b> PartialOrd<$rhs> for $lhs {
#[inline]
fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
let other: &[u8] = other.as_ref();
PartialOrd::partial_cmp(self.as_bytes(), other)
}
}
impl<'a, 'b> PartialOrd<$lhs> for $rhs {
#[inline]
fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
let this: &[u8] = self.as_ref();
PartialOrd::partial_cmp(this, other.as_bytes())
}
}
};
}
#[cfg(feature = "std")]
mod bstring {
use std::borrow::{Borrow, Cow, ToOwned};
use std::cmp::Ordering;
use std::fmt;
use std::iter::FromIterator;
use std::ops;
use crate::bstr::BStr;
use crate::bstring::BString;
use crate::ext_vec::ByteVec;
impl fmt::Display for BString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_bstr(), f)
}
}
impl fmt::Debug for BString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_bstr(), f)
}
}
impl ops::Deref for BString {
type Target = Vec<u8>;
#[inline]
fn deref(&self) -> &Vec<u8> {
&self.bytes
}
}
impl ops::DerefMut for BString {
#[inline]
fn deref_mut(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}
impl AsRef<[u8]> for BString {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl AsRef<BStr> for BString {
#[inline]
fn as_ref(&self) -> &BStr {
self.as_bstr()
}
}
impl AsMut<[u8]> for BString {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
impl AsMut<BStr> for BString {
#[inline]
fn as_mut(&mut self) -> &mut BStr {
self.as_mut_bstr()
}
}
impl Borrow<BStr> for BString {
#[inline]
fn borrow(&self) -> &BStr {
self.as_bstr()
}
}
impl ToOwned for BStr {
type Owned = BString;
#[inline]
fn to_owned(&self) -> BString {
BString::from(self)
}
}
impl Default for BString {
fn default() -> BString {
BString::from(vec![])
}
}
impl<'a> From<&'a [u8]> for BString {
#[inline]
fn from(s: &'a [u8]) -> BString {
BString::from(s.to_vec())
}
}
impl From<Vec<u8>> for BString {
#[inline]
fn from(s: Vec<u8>) -> BString {
BString { bytes: s }
}
}
impl From<BString> for Vec<u8> {
#[inline]
fn from(s: BString) -> Vec<u8> {
s.bytes
}
}
impl<'a> From<&'a str> for BString {
#[inline]
fn from(s: &'a str) -> BString {
BString::from(s.as_bytes().to_vec())
}
}
impl From<String> for BString {
#[inline]
fn from(s: String) -> BString {
BString::from(s.into_bytes())
}
}
impl<'a> From<&'a BStr> for BString {
#[inline]
fn from(s: &'a BStr) -> BString {
BString::from(s.bytes.to_vec())
}
}
impl<'a> From<BString> for Cow<'a, BStr> {
#[inline]
fn from(s: BString) -> Cow<'a, BStr> {
Cow::Owned(s)
}
}
impl FromIterator<char> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> BString {
BString::from(iter.into_iter().collect::<String>())
}
}
impl FromIterator<u8> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> BString {
BString::from(iter.into_iter().collect::<Vec<u8>>())
}
}
impl<'a> FromIterator<&'a str> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> BString {
let mut buf = vec![];
for b in iter {
buf.push_str(b);
}
BString::from(buf)
}
}
impl<'a> FromIterator<&'a [u8]> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> BString {
let mut buf = vec![];
for b in iter {
buf.push_str(b);
}
BString::from(buf)
}
}
impl<'a> FromIterator<&'a BStr> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a BStr>>(iter: T) -> BString {
let mut buf = vec![];
for b in iter {
buf.push_str(b);
}
BString::from(buf)
}
}
impl FromIterator<BString> for BString {
#[inline]
fn from_iter<T: IntoIterator<Item = BString>>(iter: T) -> BString {
let mut buf = vec![];
for b in iter {
buf.push_str(b);
}
BString::from(buf)
}
}
impl Eq for BString {}
impl PartialEq for BString {
#[inline]
fn eq(&self, other: &BString) -> bool {
&self[..] == &other[..]
}
}
impl_partial_eq!(BString, Vec<u8>);
impl_partial_eq!(BString, [u8]);
impl_partial_eq!(BString, &'a [u8]);
impl_partial_eq!(BString, String);
impl_partial_eq!(BString, str);
impl_partial_eq!(BString, &'a str);
impl_partial_eq!(BString, BStr);
impl_partial_eq!(BString, &'a BStr);
impl PartialOrd for BString {
#[inline]
fn partial_cmp(&self, other: &BString) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.bytes, &other.bytes)
}
}
impl Ord for BString {
#[inline]
fn cmp(&self, other: &BString) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl_partial_ord!(BString, Vec<u8>);
impl_partial_ord!(BString, [u8]);
impl_partial_ord!(BString, &'a [u8]);
impl_partial_ord!(BString, String);
impl_partial_ord!(BString, str);
impl_partial_ord!(BString, &'a str);
impl_partial_ord!(BString, BStr);
impl_partial_ord!(BString, &'a BStr);
}
mod bstr {
#[cfg(feature = "std")]
use std::borrow::Cow;
use core::cmp::Ordering;
use core::fmt;
use core::ops;
use crate::bstr::BStr;
use crate::ext_slice::ByteSlice;
impl fmt::Display for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Write the given bstr (lossily) to the given formatter.
fn write_bstr(
f: &mut fmt::Formatter<'_>,
bstr: &BStr,
) -> Result<(), fmt::Error> {
for chunk in bstr.utf8_chunks() {
f.write_str(chunk.valid())?;
if !chunk.invalid().is_empty() {
f.write_str("\u{FFFD}")?;
}
}
Ok(())
}
/// Write 'num' fill characters to the given formatter.
fn write_pads(
f: &mut fmt::Formatter<'_>,
num: usize,
) -> fmt::Result {
let fill = f.fill();
for _ in 0..num {
f.write_fmt(format_args!("{}", fill))?;
}
Ok(())
}
if let Some(align) = f.align() {
let width = f.width().unwrap_or(0);
let nchars = self.chars().count();
let remaining_pads = width.saturating_sub(nchars);
match align {
fmt::Alignment::Left => {
write_bstr(f, self)?;
write_pads(f, remaining_pads)?;
}
fmt::Alignment::Right => {
write_pads(f, remaining_pads)?;
write_bstr(f, self)?;
}
fmt::Alignment::Center => {
let half = remaining_pads / 2;
let second_half = if remaining_pads % 2 == 0 {
half
} else {
half + 1
};
write_pads(f, half)?;
write_bstr(f, self)?;
write_pads(f, second_half)?;
}
}
Ok(())
} else {
write_bstr(f, self)?;
Ok(())
}
}
}
impl fmt::Debug for BStr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "\"")?;
for (s, e, ch) in self.char_indices() {
match ch {
'\0' => write!(f, "\\0")?,
'\u{FFFD}' => {
let bytes = self[s..e].as_bytes();
if bytes == b"\xEF\xBF\xBD" {
write!(f, "{}", ch.escape_debug())?;
} else {
for &b in self[s..e].as_bytes() {
write!(f, r"\x{:02X}", b)?;
}
}
}
// ASCII control characters except \0, \n, \r, \t
'\x01'..='\x08'
| '\x0b'
| '\x0c'
| '\x0e'..='\x19'
| '\x7f' => {
write!(f, "\\x{:02x}", ch as u32)?;
}
'\n' | '\r' | '\t' | _ => {
write!(f, "{}", ch.escape_debug())?;
}
}
}
write!(f, "\"")?;
Ok(())
}
}
impl ops::Deref for BStr {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
&self.bytes
}
}
impl ops::DerefMut for BStr {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
impl ops::Index<usize> for BStr {
type Output = u8;
#[inline]
fn index(&self, idx: usize) -> &u8 {
&self.as_bytes()[idx]
}
}
impl ops::Index<ops::RangeFull> for BStr {
type Output = BStr;
#[inline]
fn index(&self, _: ops::RangeFull) -> &BStr {
self
}
}
impl ops::Index<ops::Range<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::Range<usize>) -> &BStr {
BStr::new(&self.as_bytes()[r.start..r.end])
}
}
impl ops::Index<ops::RangeInclusive<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeInclusive<usize>) -> &BStr {
BStr::new(&self.as_bytes()[*r.start()..=*r.end()])
}
}
impl ops::Index<ops::RangeFrom<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeFrom<usize>) -> &BStr {
BStr::new(&self.as_bytes()[r.start..])
}
}
impl ops::Index<ops::RangeTo<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeTo<usize>) -> &BStr {
BStr::new(&self.as_bytes()[..r.end])
}
}
impl ops::Index<ops::RangeToInclusive<usize>> for BStr {
type Output = BStr;
#[inline]
fn index(&self, r: ops::RangeToInclusive<usize>) -> &BStr {
BStr::new(&self.as_bytes()[..=r.end])
}
}
impl ops::IndexMut<usize> for BStr {
#[inline]
fn index_mut(&mut self, idx: usize) -> &mut u8 {
&mut self.bytes[idx]
}
}
impl ops::IndexMut<ops::RangeFull> for BStr {
#[inline]
fn index_mut(&mut self, _: ops::RangeFull) -> &mut BStr {
self
}
}
impl ops::IndexMut<ops::Range<usize>> for BStr {
#[inline]
fn index_mut(&mut self, r: ops::Range<usize>) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes[r.start..r.end])
}
}
impl ops::IndexMut<ops::RangeInclusive<usize>> for BStr {
#[inline]
fn index_mut(&mut self, r: ops::RangeInclusive<usize>) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes[*r.start()..=*r.end()])
}
}
impl ops::IndexMut<ops::RangeFrom<usize>> for BStr {
#[inline]
fn index_mut(&mut self, r: ops::RangeFrom<usize>) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes[r.start..])
}
}
impl ops::IndexMut<ops::RangeTo<usize>> for BStr {
#[inline]
fn index_mut(&mut self, r: ops::RangeTo<usize>) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes[..r.end])
}
}
impl ops::IndexMut<ops::RangeToInclusive<usize>> for BStr {
#[inline]
fn index_mut(&mut self, r: ops::RangeToInclusive<usize>) -> &mut BStr {
BStr::from_bytes_mut(&mut self.bytes[..=r.end])
}
}
impl AsRef<[u8]> for BStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl AsRef<BStr> for [u8] {
#[inline]
fn as_ref(&self) -> &BStr {
BStr::new(self)
}
}
impl AsRef<BStr> for str {
#[inline]
fn as_ref(&self) -> &BStr {
BStr::new(self)
}
}
impl AsMut<[u8]> for BStr {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
&mut self.bytes
}
}
impl AsMut<BStr> for [u8] {
#[inline]
fn as_mut(&mut self) -> &mut BStr {
BStr::new_mut(self)
}
}
impl<'a> Default for &'a BStr {
fn default() -> &'a BStr {
BStr::from_bytes(b"")
}
}
impl<'a> Default for &'a mut BStr {
fn default() -> &'a mut BStr {
BStr::from_bytes_mut(&mut [])
}
}
impl<'a> From<&'a [u8]> for &'a BStr {
#[inline]
fn from(s: &'a [u8]) -> &'a BStr {
BStr::from_bytes(s)
}
}
impl<'a> From<&'a str> for &'a BStr {
#[inline]
fn from(s: &'a str) -> &'a BStr {
BStr::from_bytes(s.as_bytes())
}
}
#[cfg(feature = "std")]
impl<'a> From<&'a BStr> for Cow<'a, BStr> {
#[inline]
fn from(s: &'a BStr) -> Cow<'a, BStr> {
Cow::Borrowed(s)
}
}
#[cfg(feature = "std")]
impl From<Box<[u8]>> for Box<BStr> {
#[inline]
fn from(s: Box<[u8]>) -> Box<BStr> {
BStr::from_boxed_bytes(s)
}
}
#[cfg(feature = "std")]
impl From<Box<BStr>> for Box<[u8]> {
#[inline]
fn from(s: Box<BStr>) -> Box<[u8]> {
BStr::into_boxed_bytes(s)
}
}
impl Eq for BStr {}
impl PartialEq<BStr> for BStr {
#[inline]
fn eq(&self, other: &BStr) -> bool {
self.as_bytes() == other.as_bytes()
}
}
impl_partial_eq!(BStr, [u8]);
impl_partial_eq!(BStr, &'a [u8]);
impl_partial_eq!(BStr, str);
impl_partial_eq!(BStr, &'a str);
#[cfg(feature = "std")]
impl_partial_eq!(BStr, Vec<u8>);
#[cfg(feature = "std")]
impl_partial_eq!(&'a BStr, Vec<u8>);
#[cfg(feature = "std")]
impl_partial_eq!(BStr, String);
#[cfg(feature = "std")]
impl_partial_eq!(&'a BStr, String);
#[cfg(feature = "std")]
impl_partial_eq_cow!(&'a BStr, Cow<'a, BStr>);
#[cfg(feature = "std")]
impl_partial_eq_cow!(&'a BStr, Cow<'a, str>);
#[cfg(feature = "std")]
impl_partial_eq_cow!(&'a BStr, Cow<'a, [u8]>);
impl PartialOrd for BStr {
#[inline]
fn partial_cmp(&self, other: &BStr) -> Option<Ordering> {
PartialOrd::partial_cmp(self.as_bytes(), other.as_bytes())
}
}
impl Ord for BStr {
#[inline]
fn cmp(&self, other: &BStr) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl_partial_ord!(BStr, [u8]);
impl_partial_ord!(BStr, &'a [u8]);
impl_partial_ord!(BStr, str);
impl_partial_ord!(BStr, &'a str);
#[cfg(feature = "std")]
impl_partial_ord!(BStr, Vec<u8>);
#[cfg(feature = "std")]
impl_partial_ord!(&'a BStr, Vec<u8>);
#[cfg(feature = "std")]
impl_partial_ord!(BStr, String);
#[cfg(feature = "std")]
impl_partial_ord!(&'a BStr, String);
}
#[cfg(feature = "serde1-nostd")]
mod bstr_serde {
use core::fmt;
use serde::{
de::Error, de::Visitor, Deserialize, Deserializer, Serialize,
Serializer,
};
use crate::bstr::BStr;
impl Serialize for BStr {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.as_bytes())
}
}
impl<'a, 'de: 'a> Deserialize<'de> for &'a BStr {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<&'a BStr, D::Error>
where
D: Deserializer<'de>,
{
struct BStrVisitor;
impl<'de> Visitor<'de> for BStrVisitor {
type Value = &'de BStr;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a borrowed byte string")
}
#[inline]
fn visit_borrowed_bytes<E: Error>(
self,
value: &'de [u8],
) -> Result<&'de BStr, E> {
Ok(BStr::new(value))
}
#[inline]
fn visit_borrowed_str<E: Error>(
self,
value: &'de str,
) -> Result<&'de BStr, E> {
Ok(BStr::new(value))
}
}
deserializer.deserialize_bytes(BStrVisitor)
}
}
}
#[cfg(feature = "serde1")]
mod bstring_serde {
use std::cmp;
use std::fmt;
use serde::{
de::Error, de::SeqAccess, de::Visitor, Deserialize, Deserializer,
Serialize, Serializer,
};
use crate::bstring::BString;
impl Serialize for BString {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.as_bytes())
}
}
impl<'de> Deserialize<'de> for BString {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<BString, D::Error>
where
D: Deserializer<'de>,
{
struct BStringVisitor;
impl<'de> Visitor<'de> for BStringVisitor {
type Value = BString;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a byte string")
}
#[inline]
fn visit_seq<V: SeqAccess<'de>>(
self,
mut visitor: V,
) -> Result<BString, V::Error> {
let len = cmp::min(visitor.size_hint().unwrap_or(0), 256);
let mut bytes = Vec::with_capacity(len);
while let Some(v) = visitor.next_element()? {
bytes.push(v);
}
Ok(BString::from(bytes))
}
#[inline]
fn visit_bytes<E: Error>(
self,
value: &[u8],
) -> Result<BString, E> {
Ok(BString::from(value))
}
#[inline]
fn visit_byte_buf<E: Error>(
self,
value: Vec<u8>,
) -> Result<BString, E> {
Ok(BString::from(value))
}
#[inline]
fn visit_str<E: Error>(
self,
value: &str,
) -> Result<BString, E> {
Ok(BString::from(value))
}
#[inline]
fn visit_string<E: Error>(
self,
value: String,
) -> Result<BString, E> {
Ok(BString::from(value))
}
}
deserializer.deserialize_byte_buf(BStringVisitor)
}
}
}
#[cfg(test)]
mod display {
use crate::bstring::BString;
use crate::ByteSlice;
#[test]
fn clean() {
assert_eq!(&format!("{}", &b"abc".as_bstr()), "abc");
assert_eq!(&format!("{}", &b"\xf0\x28\x8c\xbc".as_bstr()), "�(��");
}
#[test]
fn width_bigger_than_bstr() {
assert_eq!(&format!("{:<7}!", &b"abc".as_bstr()), "abc !");
assert_eq!(&format!("{:>7}!", &b"abc".as_bstr()), " abc!");
assert_eq!(&format!("{:^7}!", &b"abc".as_bstr()), " abc !");
assert_eq!(&format!("{:^6}!", &b"abc".as_bstr()), " abc !");
assert_eq!(&format!("{:-<7}!", &b"abc".as_bstr()), "abc----!");
assert_eq!(&format!("{:->7}!", &b"abc".as_bstr()), "----abc!");
assert_eq!(&format!("{:-^7}!", &b"abc".as_bstr()), "--abc--!");
assert_eq!(&format!("{:-^6}!", &b"abc".as_bstr()), "-abc--!");
assert_eq!(
&format!("{:<7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(�� !"
);
assert_eq!(
&format!("{:>7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
" �(��!"
);
assert_eq!(
&format!("{:^7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
" �(�� !"
);
assert_eq!(
&format!("{:^6}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
" �(�� !"
);
assert_eq!(
&format!("{:-<7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��---!"
);
assert_eq!(
&format!("{:->7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"---�(��!"
);
assert_eq!(
&format!("{:-^7}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"-�(��--!"
);
assert_eq!(
&format!("{:-^6}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"-�(��-!"
);
}
#[test]
fn width_lesser_than_bstr() {
assert_eq!(&format!("{:<2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(&format!("{:>2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(&format!("{:^2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(&format!("{:-<2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(&format!("{:->2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(&format!("{:-^2}!", &b"abc".as_bstr()), "abc!");
assert_eq!(
&format!("{:<3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:>3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:^3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:^2}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:-<3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:->3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:-^3}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
assert_eq!(
&format!("{:-^2}!", &b"\xf0\x28\x8c\xbc".as_bstr()),
"�(��!"
);
}
quickcheck::quickcheck! {
fn total_length(bstr: BString) -> bool {
let size = bstr.chars().count();
format!("{:<1$}", bstr.as_bstr(), size).chars().count() >= size
}
}
}
#[cfg(test)]
mod bstring_arbitrary {
use crate::bstring::BString;
use quickcheck::{Arbitrary, Gen};
impl Arbitrary for BString {
fn arbitrary(g: &mut Gen) -> BString {
BString::from(Vec::<u8>::arbitrary(g))
}
fn shrink(&self) -> Box<dyn Iterator<Item = BString>> {
Box::new(self.bytes.shrink().map(BString::from))
}
}
}
#[test]
fn test_debug() {
use crate::{ByteSlice, B};
assert_eq!(
r#""\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp""#,
format!("{:?}", b"\0\0\0 ftypisom\0\0\x02\0isomiso2avc1mp".as_bstr()),
);
// Tests that if the underlying bytes contain the UTF-8 encoding of the
// replacement codepoint, then we emit the codepoint just like other
// non-printable Unicode characters.
assert_eq!(
b"\"\\xFF\xEF\xBF\xBD\\xFF\"".as_bstr(),
// Before fixing #72, the output here would be:
// \\xFF\\xEF\\xBF\\xBD\\xFF
B(&format!("{:?}", b"\xFF\xEF\xBF\xBD\xFF".as_bstr())).as_bstr(),
);
}
// See: https://github.com/BurntSushi/bstr/issues/82
#[test]
fn test_cows_regression() {
use crate::ByteSlice;
use std::borrow::Cow;
let c1 = Cow::from(b"hello bstr".as_bstr());
let c2 = b"goodbye bstr".as_bstr();
assert_ne!(c1, c2);
let c3 = Cow::from("hello str");
let c4 = "goodbye str";
assert_ne!(c3, c4);
}