use crate::converters::Base;
use crate::converters::Case;
use crate::converters::atoi_unsigned;
use crate::converters::itoa_signed;
use crate::converters::itoa_unsigned;
#[derive(Debug, Clone)]
pub enum FormatDirection {
Left(usize),
Center(usize),
Right(usize),
None,
}
#[derive(Debug, Clone)]
pub struct FormatOptions {
pub padding: FormatDirection,
pub filling: Option<char>,
}
impl FormatOptions {
pub fn new(
padding: FormatDirection,
filling: Option<char>,
) -> FormatOptions {
FormatOptions {
padding: padding,
filling: filling,
}
}
pub fn get_padding(&self) -> &FormatDirection {
&self.padding
}
pub fn get_filling(&self) -> &Option<char> {
&self.filling
}
pub fn set_padding(
&mut self,
padding: FormatDirection,
) -> &mut FormatOptions {
self.padding = padding;
self
}
pub fn set_filling(
&mut self,
filling: Option<char>,
) -> &mut FormatOptions {
self.filling = filling;
self
}
pub fn get_fields(&self) -> (&FormatDirection, &Option<char>) {
(&self.padding, &self.filling)
}
pub fn set_fields(
&mut self,
options: (FormatDirection, Option<char>),
) -> &mut FormatOptions {
self.padding = options.0;
self.filling = options.1;
self
}
}
pub fn format_text(
text: &String,
options: FormatOptions,
) -> String {
let filling = options
.filling
.unwrap_or(' ');
let mut result = text.clone();
match options.padding {
FormatDirection::Left(width) => {
let mut width = width;
let length = text.len();
if width < length {
return result;
}
width -= length;
result.push_str(&String::from(filling).repeat(width).as_str());
},
FormatDirection::Center(_width) => {
},
FormatDirection::Right(width) => {
let mut width = width;
let length = text.len();
if width < length {
return result;
}
width -= length;
result.insert_str(0, String::from(filling)
.repeat(width)
.as_str());
},
_ => {},
}
result
}
#[derive(Debug, Clone)]
pub enum CFormatArgument {
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
IntSize(isize),
UInt8(u8),
UInt16(u16),
UInt32(u32),
UInt64(u64),
UIntSize(usize),
Character(char),
String(String),
Pointer(*const u8),
}
#[derive(Debug, Clone)]
pub enum CFormatTypeSpecifier {
Integer,
Octal,
Unsigned,
LowerHex,
UpperHex,
Character,
ByteInt,
ByteLowerHex,
ByteUpperHex,
ByteOctal,
ByteUnsigned,
ShortInt,
ShortLowerHex,
ShortUpperHex,
ShortOctal,
ShortUnsigned,
LongInt,
LongLowerHex,
LongUpperHex,
LongOctal,
LongUnsigned,
LongLongInt,
LongLongLowerHex,
LongLongUpperHex,
LongLongOctal,
LongLongUnsigned,
String,
Pointer,
Escape,
None,
}
pub fn c_format(
format: String,
arguments: Vec<CFormatArgument>,
) -> String {
let mut result = String::new();
let mut format_iterator = format.chars();
let mut args_iterator = arguments.iter();
while let Some(mut character) = format_iterator.next() {
if character == '%' {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
let mut options = FormatOptions::new(FormatDirection::None, None);
match character {
'0' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
options.set_filling(Some('0'));
}
'*' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
if let CFormatArgument::IntSize(padding) = args_iterator.next().unwrap() {
options.set_padding(if *padding < 0 {
FormatDirection::Left(-*padding as usize)
} else {
FormatDirection::Right(*padding as usize)
});
} else {
continue;
}
},
'-' | '1'..='9' => {
let sign = if character == '-' {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
true
} else {
false
};
let mut padding = String::new();
loop {
if !character.is_digit(10) {
break;
}
padding.push(character);
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
}
options.set_padding(if sign {
FormatDirection::Left(atoi_unsigned(&padding, Base::new(10), false).unwrap())
} else {
FormatDirection::Right(atoi_unsigned(&padding, Base::new(10), false).unwrap())
});
},
_ => {},
}
let type_specifier = match character {
'c' => CFormatTypeSpecifier::Character,
'd' | 'i' => CFormatTypeSpecifier::Integer,
'h' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
match character {
'h' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
match character {
'd' | 'i' => CFormatTypeSpecifier::ByteInt,
'x' => CFormatTypeSpecifier::ByteLowerHex,
'X' => CFormatTypeSpecifier::ByteUpperHex,
'u' => CFormatTypeSpecifier::ByteUnsigned,
'o' => CFormatTypeSpecifier::ByteOctal,
_ => {
return result
},
}
},
'd' | 'i' => CFormatTypeSpecifier::ShortInt,
'x' => CFormatTypeSpecifier::ShortLowerHex,
'X' => CFormatTypeSpecifier::ShortUpperHex,
'u' => CFormatTypeSpecifier::ShortUnsigned,
'o' => CFormatTypeSpecifier::ShortOctal,
_ => {
return result
},
}
},
'l' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
match character {
'l' => {
character = if let Some(temp) = format_iterator.next() {
temp
} else {
return result
};
match character {
'd' | 'i' => CFormatTypeSpecifier::LongLongInt,
'x' => CFormatTypeSpecifier::LongLongLowerHex,
'X' => CFormatTypeSpecifier::LongLongUpperHex,
'u' => CFormatTypeSpecifier::LongLongUnsigned,
'o' => CFormatTypeSpecifier::LongLongOctal,
_ => {
return result
},
}
},
'd' | 'i' => CFormatTypeSpecifier::LongInt,
'x' => CFormatTypeSpecifier::LongLowerHex,
'X' => CFormatTypeSpecifier::LongUpperHex,
'u' => CFormatTypeSpecifier::LongUnsigned,
'o' => CFormatTypeSpecifier::LongOctal,
_ => {
return result
},
}
},
'o' => CFormatTypeSpecifier::Octal,
'u' => CFormatTypeSpecifier::Unsigned,
'x' => CFormatTypeSpecifier::LowerHex,
'X' => CFormatTypeSpecifier::UpperHex,
'p' => CFormatTypeSpecifier::Pointer,
's' => CFormatTypeSpecifier::String,
'%' => CFormatTypeSpecifier::Escape,
_ => CFormatTypeSpecifier::None,
};
match type_specifier {
CFormatTypeSpecifier::Character => result.push(
if let CFormatArgument::Character(temp) = args_iterator.next().unwrap() {
*temp
} else {
return result
}
),
CFormatTypeSpecifier::Integer => result.push_str(&format_text(&itoa_signed(
if let CFormatArgument::Int32(temp) = args_iterator.next().unwrap() {
*temp as isize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::Octal => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt32(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(8), Case::Lower), options).as_str()),
CFormatTypeSpecifier::Unsigned => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt32(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LowerHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt32(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Lower), options).as_str()),
CFormatTypeSpecifier::UpperHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt32(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Upper), options).as_str()),
CFormatTypeSpecifier::LongInt => result.push_str(&format_text(&itoa_signed(
if let CFormatArgument::IntSize(temp) = args_iterator.next().unwrap() {
*temp as isize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongOctal => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UIntSize(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(8), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongUnsigned => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UIntSize(temp) = args_iterator.next().unwrap() {
*temp
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongLowerHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UIntSize(temp) = args_iterator.next().unwrap() {
*temp
} else {
return result
}, Base::new(16), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongUpperHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UIntSize(temp) = args_iterator.next().unwrap() {
*temp
} else {
return result
}, Base::new(16), Case::Upper), options).as_str()),
CFormatTypeSpecifier::LongLongInt => result.push_str(&format_text(&itoa_signed(
if let CFormatArgument::Int64(temp) = args_iterator.next().unwrap() {
*temp as isize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongLongOctal => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt64(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(8), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongLongUnsigned => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt64(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongLongLowerHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt64(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Lower), options).as_str()),
CFormatTypeSpecifier::LongLongUpperHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt64(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Upper), options).as_str()),
CFormatTypeSpecifier::ShortInt => result.push_str(&format_text(&itoa_signed(
if let CFormatArgument::Int16(temp) = args_iterator.next().unwrap() {
*temp as isize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ShortOctal => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt16(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(8), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ShortUnsigned => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt16(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ShortLowerHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt16(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ShortUpperHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt16(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Upper), options).as_str()),
CFormatTypeSpecifier::ByteInt => result.push_str(&format_text(&itoa_signed(
if let CFormatArgument::Int8(temp) = args_iterator.next().unwrap() {
*temp as isize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ByteOctal => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt8(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(8), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ByteUnsigned => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt8(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(10), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ByteLowerHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt8(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Lower), options).as_str()),
CFormatTypeSpecifier::ByteUpperHex => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::UInt8(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Upper), options).as_str()),
CFormatTypeSpecifier::Pointer => result.push_str(&format_text(&itoa_unsigned(
if let CFormatArgument::Pointer(temp) = args_iterator.next().unwrap() {
*temp as usize
} else {
return result
}, Base::new(16), Case::Upper),
FormatOptions::new(FormatDirection::Right(usize::BITS as usize / u8::BITS as usize), Some('0'))).as_str()
),
CFormatTypeSpecifier::String => result.push_str(&format_text(&(
if let CFormatArgument::String(temp) = args_iterator.next().unwrap() {
temp.to_string()
} else {
return result
}), options)),
CFormatTypeSpecifier::Escape => result.push('%'),
_ => {},
}
continue;
}
result.push(character);
}
result
}