#![cfg_attr(
any(
not(feature = "repr-dump"),
all(feature = "repr-dump", feature = "repr-color")
),
doc = "```ignore"
)]
#![cfg_attr(
all(feature = "repr-dump", not(feature = "repr-color")),
doc = "```rust"
)]
use crate::{
Binary,
error::Error,
repr::{BinaryFormatOptions, ByteKind, RadixFormat, ReprComponentKind},
};
use alloc::{
format,
string::{String, ToString},
vec::Vec,
};
use core::{
clone::Clone,
convert::{AsRef, From},
default::Default,
fmt::Debug,
iter::Iterator,
marker::Copy,
option::Option::Some,
result::Result::{self, Err, Ok},
};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct StringFormatOptions {
radix_format: RadixFormat,
compact: bool,
colored: bool,
}
pub fn string_representation(value: &Binary<'_>, options: &StringFormatOptions) -> String {
let prefix = if options.colored {
let style = ReprComponentKind::Prefix.display_style(true);
format!("{style}{}{style:#}", options.radix_format.prefix_str(),)
} else {
options.radix_format.prefix_str().to_string()
};
let quote = if options.colored {
let style = ReprComponentKind::Delimiter.display_style(true);
format!("{style}\"{style:#}")
} else {
'"'.to_string()
};
let underscore = if options.colored {
let style = ReprComponentKind::Separator.display_style(true);
format!("{style}_{style:#}")
} else {
'_'.to_string()
};
let mapped = value.as_ref().iter().map(|b| {
if options.colored {
let style = ByteKind::ascii_char_display_style(b, true);
format!("{style}{}{style:#}", options.radix_format.format(b, false))
} else {
options.radix_format.format(b, false).to_string()
}
});
format!(
"{prefix}{quote}{}{quote}",
if options.compact {
mapped.collect::<String>()
} else {
mapped.collect::<Vec<_>>().join(&underscore)
}
)
}
pub fn parse_string_representation(s: &str) -> Result<Binary<'_>, Error> {
if !s.starts_with('0') {
return Err(Error::MissingRadixPrefix);
}
let s = &s[1..];
if !s.starts_with(['b', 'd', 'o', 'x', 'X']) {
return Err(Error::InvalidRadixPrefix);
}
let radix_char = s.chars().next().unwrap();
let s = &s[1..];
if !(s.starts_with('"') && s.ends_with('"')) {
return Err(Error::InvalidStringQuotes);
}
let s = &s[1..s.len() - 1];
if s.is_empty() {
Ok(Binary::from(Vec::new()))
} else {
let byte_format = RadixFormat::from(Some(radix_char))?;
let radix = byte_format.radix();
let width = byte_format.max_width();
let values: Vec<u8> = if s.contains('_') {
let mut values = Vec::new();
let bytes = s.split('_');
for byte in bytes {
values.push(u8::from_str_radix(byte, radix)?);
}
values
} else {
let mut rest = s;
let mut values = Vec::new();
while !rest.is_empty() {
if width > rest.len() {
Err(Error::InvalidRepresentation)?
}
let (value, next) = rest.split_at(width);
values.push(u8::from_str_radix(value, radix)?);
rest = next;
}
values
};
Ok(Binary::from(values))
}
}
impl From<StringFormatOptions> for BinaryFormatOptions {
fn from(value: StringFormatOptions) -> Self {
Self::String(value)
}
}
impl StringFormatOptions {
pub fn with_byte_radix_format(mut self, radix_format: RadixFormat) -> Self {
self.radix_format = radix_format;
self
}
pub fn with_binary_bytes(self) -> Self {
Self::with_byte_radix_format(self, RadixFormat::Binary)
}
pub fn with_decimal_bytes(self) -> Self {
Self::with_byte_radix_format(self, RadixFormat::Decimal)
}
pub fn with_lower_hex_bytes(self) -> Self {
Self::with_byte_radix_format(self, RadixFormat::LowerHex)
}
pub fn with_octal_bytes(self) -> Self {
Self::with_byte_radix_format(self, RadixFormat::Octal)
}
pub fn with_upper_hex_bytes(self) -> Self {
Self::with_byte_radix_format(self, RadixFormat::UpperHex)
}
pub fn compact(mut self, compact: bool) -> Self {
self.compact = compact;
self
}
#[cfg(feature = "repr-color")]
pub fn use_color(mut self, colored: bool) -> Self {
self.colored = colored;
self
}
}