use crate::graphics::{
self, get_alpha_of_u32_in_u8, get_blue_of_u32_in_u8,
get_green_of_u32_in_u8, get_red_of_u32_in_u8,
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub struct FileData {
pub raw_data: Vec<u8>,
pub expected_data_type: DataType,
}
impl FileData {
#[must_use]
pub fn to_printable(&self) -> String {
match self.expected_data_type {
DataType::Text => format!("Text: {:?}", self.to_string()),
#[cfg(feature = "font_support")]
DataType::Font => self.to_font().map_or_else(
|_| "Not a font.".into(),
|font| format!("Font: {font:?}"),
),
#[cfg(feature = "imagery")]
DataType::Image => format!("Bytes: {:?}", self.to_image()),
DataType::Audio => format!("Audio: {:?}", "<Unsupported>"),
DataType::ListOfText => {
format!("List of text: {:#?}", self.to_list_of_strings())
}
DataType::Color => self.to_color().map_or_else(
|| "Not a color.".into(),
|color| {
format!(
"Color: {:?} | r{} g{} b{} a{}",
color,
get_red_of_u32_in_u8(color),
get_green_of_u32_in_u8(color),
get_blue_of_u32_in_u8(color),
get_alpha_of_u32_in_u8(color)
)
},
),
_ => format!("Bytes: {:?}", self.as_bytes()),
}
}
}
#[cfg_attr(all(feature = "strum"), derive(strum::EnumIter))]
#[cfg_attr(feature = "bitcode", derive(bitcode::Encode, bitcode::Decode))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "c_compatible", repr(C))]
pub enum DataType {
Bytes,
Text,
#[cfg(feature = "font_support")]
Font,
#[cfg(feature = "imagery")]
Image,
Audio,
ListOfText,
Color,
}
impl FileData {
#[must_use]
pub const fn from_bytes(
data: Vec<u8>,
expected_data_type: DataType,
) -> Self {
Self {
raw_data: data,
expected_data_type,
}
}
#[must_use]
pub const fn from_string(data: String) -> Self {
Self::from_bytes(data.into_bytes(), DataType::Text)
}
#[must_use]
pub fn from_list_of_strings(value: &Vec<String>) -> Self {
Self::from_bytes(
crate::misc::strings_to_bytes(value),
DataType::ListOfText,
)
}
}
impl FileData {
pub fn to_string(&self) -> Result<String, std::string::FromUtf8Error> {
String::from_utf8(self.raw_data.clone())
}
#[cfg(feature = "font_support")]
pub fn to_font(
&self,
) -> Result<fontdue::Font, Box<dyn core::error::Error>> {
let font = fontdue::Font::from_bytes(
self.raw_data.clone(),
fontdue::FontSettings::default(),
)?;
Ok(font)
}
#[cfg(feature = "imagery")]
pub fn to_image(
&self,
) -> Result<image::DynamicImage, Box<dyn core::error::Error>> {
let img = image::load_from_memory(&self.raw_data)?;
Ok(img)
}
#[must_use]
pub const fn as_bytes(&self) -> &Vec<u8> {
&self.raw_data
}
#[must_use]
pub fn to_list_of_strings(&self) -> Option<Vec<String>> {
let data = crate::misc::bytes_to_strings(&self.raw_data.clone());
if core::intrinsics::unlikely(data.is_empty()) {
None
} else {
Some(data)
}
}
#[must_use]
pub fn to_color(&self) -> Option<u32> {
match self.raw_data.len() {
1 => Some(graphics::rgb_u8_to_u32(
self.raw_data[0],
self.raw_data[0],
self.raw_data[0],
)),
3 => Some(graphics::rgb_u8_to_u32(
self.raw_data[0],
self.raw_data[1],
self.raw_data[2],
)),
4 => Some(graphics::rgba_u8_to_u32(
self.raw_data[0],
self.raw_data[1],
self.raw_data[2],
self.raw_data[3],
)),
_ => None,
}
}
}