use std::{
io::{Read, Write},
str::FromStr,
};
use regex::Regex;
#[derive(Debug)]
pub struct Resource {
image_type: Type,
buffer: Vec<u8>,
}
impl Resource {
pub fn new(image_type: Type) -> Self {
Self {
image_type,
buffer: vec![],
}
}
pub fn as_bytes(&self) -> &[u8] {
self.buffer.as_slice()
}
pub fn filename(&self) -> String {
self.image_type.to_string()
}
pub fn get_type(&self) -> Type {
self.image_type.clone()
}
}
impl Write for Resource {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.buffer.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.buffer.flush()
}
}
impl Read for Resource {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
buf.as_mut().write(&self.buffer)
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Version {
Standard,
Size2X,
Size3X,
}
impl ToString for Version {
fn to_string(&self) -> String {
match self {
Version::Standard => "".into(),
Version::Size2X => "@2x".into(),
Version::Size3X => "@3x".into(),
}
}
}
impl FromStr for Version {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"" => Ok(Version::Standard),
"@2x" => Ok(Version::Size2X),
"@3x" => Ok(Version::Size3X),
_ => Err(()),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Type {
Background(Version),
Footer(Version),
Icon(Version),
Logo(Version),
Strip(Version),
Thumbnail(Version),
}
impl ToString for Type {
fn to_string(&self) -> String {
match self {
Type::Background(v) => format!("background{}.png", v.to_string()),
Type::Footer(v) => format!("footer{}.png", v.to_string()),
Type::Icon(v) => format!("icon{}.png", v.to_string()),
Type::Logo(v) => format!("logo{}.png", v.to_string()),
Type::Strip(v) => format!("strip{}.png", v.to_string()),
Type::Thumbnail(v) => format!("thumbnail{}.png", v.to_string()),
}
}
}
impl FromStr for Type {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let re = Regex::new(r"(?P<type>\w+)(?P<version>@\dx)?\.(?P<format>png)").unwrap();
let captures = re.captures(&s);
if let Some(captures) = captures {
let version = if let Some(version) = captures.name("version") {
version
.as_str()
.parse::<Version>()
.unwrap_or(Version::Standard)
} else {
Version::Standard
};
if let Ok(image_type_str) = captures["type"].parse::<String>() {
match image_type_str.as_str() {
"background" => Ok(Type::Background(version)),
"footer" => Ok(Type::Footer(version)),
"icon" => Ok(Type::Icon(version)),
"logo" => Ok(Type::Logo(version)),
"strip" => Ok(Type::Strip(version)),
"thumbnail" => Ok(Type::Thumbnail(version)),
_ => Err(()),
}
} else {
Err(())
}
} else {
Err(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_resource() {
let mut data = [0u8; 2048];
let mut resource = Resource::new(Type::Icon(Version::Standard));
resource.write(&mut data).unwrap();
println!("{}", resource.buffer.len());
assert_eq!(resource.buffer.len(), 2048);
assert_eq!(resource.get_type(), Type::Icon(Version::Standard));
}
#[test]
fn check_type_string() {
let t = Type::Footer(Version::Standard);
assert_eq!("footer.png", t.to_string());
let t = Type::Logo(Version::Size2X);
assert_eq!("logo@2x.png", t.to_string());
}
#[test]
fn check_type_from_string() {
let t = "footer.png".parse::<Type>().unwrap();
assert_eq!(Type::Footer(Version::Standard), t);
let t = Type::from_str("logo@2x.png").unwrap();
assert_eq!(Type::Logo(Version::Size2X), t);
}
}