use std::iter::Iterator;
use std::marker::Send;
use std::string::ToString;
const DEFAULT_SEPARATOR: &str = ":";
pub trait BufferFormatter: Send + 'static {
fn get_separator(&self) -> &str;
fn format_byte(&self, byte: &u8) -> String;
fn format_buffer(&self, buffer: &[u8]) -> String {
buffer
.iter()
.map(|b| self.format_byte(b))
.collect::<Vec<String>>()
.join(self.get_separator())
}
}
impl BufferFormatter for Box<dyn BufferFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
#[derive(Debug, Clone)]
pub struct DecimalFormatter {
separator: String,
}
impl DecimalFormatter {
pub fn new(provided_separator: Option<&str>) -> Self {
Self::new_owned(provided_separator.map(ToString::to_string))
}
pub fn new_owned(provided_separator: Option<String>) -> Self {
Self {
separator: provided_separator.unwrap_or(DEFAULT_SEPARATOR.to_string()),
}
}
pub fn new_default() -> Self {
Self::new_owned(None)
}
}
impl BufferFormatter for DecimalFormatter {
fn get_separator(&self) -> &str {
self.separator.as_str()
}
fn format_byte(&self, byte: &u8) -> String {
format!("{byte}")
}
}
impl BufferFormatter for Box<DecimalFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
impl Default for DecimalFormatter {
fn default() -> Self {
Self::new_default()
}
}
#[derive(Debug, Clone)]
pub struct OctalFormatter {
separator: String,
}
impl OctalFormatter {
pub fn new(provided_separator: Option<&str>) -> Self {
Self::new_owned(provided_separator.map(ToString::to_string))
}
pub fn new_owned(provided_separator: Option<String>) -> Self {
Self {
separator: provided_separator.unwrap_or(DEFAULT_SEPARATOR.to_string()),
}
}
pub fn new_default() -> Self {
Self::new_owned(None)
}
}
impl BufferFormatter for OctalFormatter {
fn get_separator(&self) -> &str {
self.separator.as_str()
}
fn format_byte(&self, byte: &u8) -> String {
format!("{byte:03o}")
}
}
impl BufferFormatter for Box<OctalFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
impl Default for OctalFormatter {
fn default() -> Self {
Self::new_default()
}
}
#[derive(Debug, Clone)]
pub struct UppercaseHexadecimalFormatter {
separator: String,
}
impl UppercaseHexadecimalFormatter {
pub fn new(provided_separator: Option<&str>) -> Self {
Self::new_owned(provided_separator.map(ToString::to_string))
}
pub fn new_owned(provided_separator: Option<String>) -> Self {
Self {
separator: provided_separator.unwrap_or(DEFAULT_SEPARATOR.to_string()),
}
}
pub fn new_default() -> Self {
Self::new_owned(None)
}
}
impl BufferFormatter for UppercaseHexadecimalFormatter {
fn get_separator(&self) -> &str {
self.separator.as_str()
}
fn format_byte(&self, byte: &u8) -> String {
format!("{byte:02X}")
}
}
impl BufferFormatter for Box<UppercaseHexadecimalFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
impl Default for UppercaseHexadecimalFormatter {
fn default() -> Self {
Self::new_default()
}
}
#[derive(Debug, Clone)]
pub struct LowercaseHexadecimalFormatter {
separator: String,
}
impl LowercaseHexadecimalFormatter {
pub fn new(provided_separator: Option<&str>) -> Self {
Self::new_owned(provided_separator.map(ToString::to_string))
}
pub fn new_owned(provided_separator: Option<String>) -> Self {
Self {
separator: provided_separator.unwrap_or(DEFAULT_SEPARATOR.to_string()),
}
}
pub fn new_default() -> Self {
Self::new_owned(None)
}
}
impl BufferFormatter for LowercaseHexadecimalFormatter {
fn get_separator(&self) -> &str {
self.separator.as_str()
}
fn format_byte(&self, byte: &u8) -> String {
format!("{byte:02x}")
}
}
impl BufferFormatter for Box<LowercaseHexadecimalFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
impl Default for LowercaseHexadecimalFormatter {
fn default() -> Self {
Self::new_default()
}
}
#[derive(Debug, Clone)]
pub struct BinaryFormatter {
separator: String,
}
impl BinaryFormatter {
pub fn new(provided_separator: Option<&str>) -> Self {
Self::new_owned(provided_separator.map(ToString::to_string))
}
pub fn new_owned(provided_separator: Option<String>) -> Self {
Self {
separator: provided_separator.unwrap_or(DEFAULT_SEPARATOR.to_string()),
}
}
pub fn new_default() -> Self {
Self::new_owned(None)
}
}
impl BufferFormatter for BinaryFormatter {
fn get_separator(&self) -> &str {
self.separator.as_str()
}
fn format_byte(&self, byte: &u8) -> String {
format!("{byte:08b}")
}
}
impl BufferFormatter for Box<BinaryFormatter> {
fn get_separator(&self) -> &str {
(**self).get_separator()
}
fn format_byte(&self, byte: &u8) -> String {
(**self).format_byte(byte)
}
}
impl Default for BinaryFormatter {
fn default() -> Self {
Self::new_default()
}
}
#[cfg(test)]
mod tests {
use crate::buffer_formatter::BinaryFormatter;
use crate::buffer_formatter::BufferFormatter;
use crate::buffer_formatter::DecimalFormatter;
use crate::buffer_formatter::LowercaseHexadecimalFormatter;
use crate::buffer_formatter::OctalFormatter;
use crate::buffer_formatter::UppercaseHexadecimalFormatter;
use std::convert::From;
use std::marker::Send;
use std::marker::Unpin;
const FORMATTING_TEST_VALUES: &[u8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18];
#[test]
fn test_buffer_formatting() {
let lowercase_hexadecimal = LowercaseHexadecimalFormatter::new_default();
let uppercase_hexadecimal = UppercaseHexadecimalFormatter::new_default();
let decimal = DecimalFormatter::new_default();
let octal = OctalFormatter::new_default();
let binary = BinaryFormatter::new_default();
assert_eq!(
lowercase_hexadecimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("0a:0b:0c:0d:0e:0f:10:11:12")
);
assert_eq!(
uppercase_hexadecimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("0A:0B:0C:0D:0E:0F:10:11:12")
);
assert_eq!(
decimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("10:11:12:13:14:15:16:17:18")
);
assert_eq!(
octal.format_buffer(FORMATTING_TEST_VALUES),
String::from("012:013:014:015:016:017:020:021:022")
);
assert_eq!(
binary.format_buffer(FORMATTING_TEST_VALUES),
String::from(
"00001010:00001011:00001100:00001101:00001110:00001111:00010000:00010001:00010010"
)
);
}
#[test]
fn test_custom_separator() {
let lowercase_hexadecimal = LowercaseHexadecimalFormatter::new(Some("-"));
let uppercase_hexadecimal = UppercaseHexadecimalFormatter::new(Some("-"));
let decimal = DecimalFormatter::new(Some("-"));
let octal = OctalFormatter::new(Some("-"));
let binary = BinaryFormatter::new(Some("-"));
assert_eq!(
lowercase_hexadecimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("0a-0b-0c-0d-0e-0f-10-11-12")
);
assert_eq!(
uppercase_hexadecimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("0A-0B-0C-0D-0E-0F-10-11-12")
);
assert_eq!(
decimal.format_buffer(FORMATTING_TEST_VALUES),
String::from("10-11-12-13-14-15-16-17-18")
);
assert_eq!(
octal.format_buffer(FORMATTING_TEST_VALUES),
String::from("012-013-014-015-016-017-020-021-022")
);
assert_eq!(
binary.format_buffer(FORMATTING_TEST_VALUES),
String::from(
"00001010-00001011-00001100-00001101-00001110-00001111-00010000-00010001-00010010"
)
);
}
fn assert_unpin<T: Unpin>() {}
#[test]
fn test_unpin() {
assert_unpin::<BinaryFormatter>();
assert_unpin::<DecimalFormatter>();
assert_unpin::<LowercaseHexadecimalFormatter>();
assert_unpin::<UppercaseHexadecimalFormatter>();
assert_unpin::<OctalFormatter>();
}
#[test]
fn test_trait_object_safety() {
let lowercase_hexadecimal: Box<dyn BufferFormatter> =
Box::new(LowercaseHexadecimalFormatter::new(None));
let uppercase_hexadecimal: Box<dyn BufferFormatter> =
Box::new(UppercaseHexadecimalFormatter::new(None));
let decimal: Box<dyn BufferFormatter> = Box::new(DecimalFormatter::new(None));
let octal: Box<dyn BufferFormatter> = Box::new(OctalFormatter::new(None));
let binary: Box<dyn BufferFormatter> = Box::new(BinaryFormatter::new(None));
_ = lowercase_hexadecimal.get_separator();
_ = lowercase_hexadecimal.format_buffer(b"qwertyuiop");
_ = uppercase_hexadecimal.get_separator();
_ = uppercase_hexadecimal.format_buffer(b"qwertyuiop");
_ = decimal.get_separator();
_ = decimal.format_buffer(b"qwertyuiop");
_ = octal.get_separator();
_ = octal.format_buffer(b"qwertyuiop");
_ = binary.get_separator();
_ = binary.format_buffer(b"qwertyuiop");
}
fn assert_buffer_formatter<T: BufferFormatter>() {}
#[test]
fn test_box() {
assert_buffer_formatter::<Box<dyn BufferFormatter>>();
assert_buffer_formatter::<Box<LowercaseHexadecimalFormatter>>();
assert_buffer_formatter::<Box<UppercaseHexadecimalFormatter>>();
assert_buffer_formatter::<Box<DecimalFormatter>>();
assert_buffer_formatter::<Box<OctalFormatter>>();
assert_buffer_formatter::<Box<BinaryFormatter>>();
}
fn assert_send<T: Send>() {}
#[test]
fn test_send() {
assert_send::<LowercaseHexadecimalFormatter>();
assert_send::<UppercaseHexadecimalFormatter>();
assert_send::<DecimalFormatter>();
assert_send::<OctalFormatter>();
assert_send::<BinaryFormatter>();
assert_send::<Box<dyn BufferFormatter>>();
assert_send::<Box<LowercaseHexadecimalFormatter>>();
assert_send::<Box<UppercaseHexadecimalFormatter>>();
assert_send::<Box<DecimalFormatter>>();
assert_send::<Box<OctalFormatter>>();
assert_send::<Box<BinaryFormatter>>();
}
}