use std::{fmt, fs::File, io::Read};
use serde::{de::{self, Visitor}, Deserialize, Deserializer, Serialize, Serializer};
use base64::prelude::*;
use crate::prelude::*;
#[derive(Debug, Clone)]
pub struct YBytes(Vec<u8>);
impl YBytes {
pub fn new(data: Vec<u8>) -> YBytes {
YBytes(data)
}
pub fn data(&self) -> &Vec<u8> {
&self.0
}
pub fn into_vec(self) -> Vec<u8> {
self.0
}
pub fn length(&self) -> usize {
self.0.len()
}
pub fn md5(&self) -> String {
format!("{:x}", md5::compute(&self.0))
}
pub fn to_str(&self) -> YRes<String> {
String::from_utf8(self.0.clone()).map_err(|e|
err!("deserialize YBytes as utf-8 text failed").trace(
ctx!("deserialize YBytes as utf-8 text: String::from_utf8() failed", e)
)
)
}
pub fn base64(&self) -> String {
BASE64_STANDARD.encode(&self.0)
}
pub fn from_base64(base64_str: &str) -> YRes<YBytes> {
let data = BASE64_STANDARD.decode(base64_str).map_err(|e|
err!("build YBytes from base64 string failed").trace(
ctx!("build YBytes from base64 string: -> BASE64_STANDARD.decode failed", e)
)
)?;
Ok(YBytes(data))
}
pub fn open_file(file_path: &str) -> YRes<YBytes> {
let mut file = File::open(file_path).map_err(|e|
err!("build YBytes from file content failed").trace(
ctx!("build YBytes from file content -> open file: File::open failed", file_path, e)
)
)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).map_err(|e|
err!("build YBytes from file content failed").trace(
ctx!("build YBytes from file content -> read file content: file.read_to_end failed", file_path, e)
)
)?;
Ok(YBytes::new(bytes))
}
}
impl Serialize for YBytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
serializer.serialize_str(&self.base64())
}
}
impl<'de> Deserialize<'de> for YBytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
struct YBytesVisitor;
impl<'de> Visitor<'de> for YBytesVisitor {
type Value = YBytes;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a base64 encoded string")
}
fn visit_str<E>(self, value: &str) -> Result<YBytes, E> where E: de::Error {
BASE64_STANDARD.decode(value).map(YBytes).map_err(de::Error::custom)
}
}
deserializer.deserialize_str(YBytesVisitor)
}
}