use encoding_rs::mem::{decode_latin1, encode_latin1_lossy};
#[derive(Debug, PartialEq, Clone)]
pub struct Vertex3dNoTex2 {
pub x: f32,
pub y: f32,
pub z: f32,
pub nx: f32,
pub ny: f32,
pub nz: f32,
pub tu: f32,
pub tv: f32,
}
impl Vertex3dNoTex2 {
pub(crate) fn to_vpx_bytes(&self) -> [u8; 32] {
let mut b = [0u8; 32];
let mut offset = 0;
for &value in &[
self.x, self.y, self.z, self.nx, self.ny, self.nz, self.tu, self.tv,
] {
b[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
offset += 4;
}
b
}
#[cfg(test)]
pub(crate) fn as_vpx_bytes(&self) -> [u8; 32] {
self.to_vpx_bytes()
}
#[cfg(test)]
pub(crate) fn from_vpx_bytes(b: &[u8; 32]) -> Self {
Vertex3dNoTex2 {
x: f32::from_le_bytes([b[0], b[1], b[2], b[3]]),
y: f32::from_le_bytes([b[4], b[5], b[6], b[7]]),
z: f32::from_le_bytes([b[8], b[9], b[10], b[11]]),
nx: f32::from_le_bytes([b[12], b[13], b[14], b[15]]),
ny: f32::from_le_bytes([b[16], b[17], b[18], b[19]]),
nz: f32::from_le_bytes([b[20], b[21], b[22], b[23]]),
tu: f32::from_le_bytes([b[24], b[25], b[26], b[27]]),
tv: f32::from_le_bytes([b[28], b[29], b[30], b[31]]),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum StringEncoding {
Latin1,
Utf8,
}
#[derive(Debug, PartialEq, Clone)]
pub struct StringWithEncoding {
pub encoding: StringEncoding,
pub string: String,
}
impl StringWithEncoding {
pub fn new(string: impl Into<String>) -> StringWithEncoding {
StringWithEncoding {
encoding: StringEncoding::Utf8,
string: string.into(),
}
}
pub fn from(s: &str) -> StringWithEncoding {
StringWithEncoding {
encoding: StringEncoding::Utf8,
string: s.to_owned(),
}
}
pub fn empty() -> StringWithEncoding {
StringWithEncoding {
encoding: StringEncoding::Utf8,
string: String::new(),
}
}
}
impl From<&[u8]> for StringWithEncoding {
fn from(data: &[u8]) -> Self {
match String::from_utf8(data.to_vec()) {
Ok(s) => StringWithEncoding {
encoding: StringEncoding::Utf8,
string: s.to_string(),
},
Err(_e) => StringWithEncoding {
encoding: StringEncoding::Latin1,
string: decode_latin1(data).to_string(),
},
}
}
}
impl From<Vec<u8>> for StringWithEncoding {
fn from(data: Vec<u8>) -> Self {
match String::from_utf8(data.clone()) {
Ok(s) => StringWithEncoding {
encoding: StringEncoding::Utf8,
string: s.to_string(),
},
Err(_e) => StringWithEncoding {
encoding: StringEncoding::Latin1,
string: decode_latin1(data.as_ref()).to_string(),
},
}
}
}
impl From<StringWithEncoding> for Vec<u8> {
fn from(string_with_encoding: StringWithEncoding) -> Self {
match string_with_encoding.encoding {
StringEncoding::Utf8 => string_with_encoding.string.as_bytes().to_vec(),
StringEncoding::Latin1 => encode_latin1_lossy(&string_with_encoding.string).to_vec(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_string_with_encoding_latin1() {
let bytes = vec![0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89];
let s: StringWithEncoding = bytes.clone().into();
assert_eq!(s.encoding, StringEncoding::Latin1);
println!("{:?}", s.string);
let bytes_decoded: Vec<u8> = s.into();
assert_eq!(bytes, bytes_decoded);
}
#[test]
fn test_string_with_encoding_utf8() {
let bytes = "Hello World".as_bytes().to_vec();
let s: StringWithEncoding = bytes.clone().into();
assert_eq!(s.encoding, StringEncoding::Utf8);
let bytes_decoded: Vec<u8> = s.into();
assert_eq!(bytes, bytes_decoded);
}
#[test]
fn test_vertex3d_no_tex2_serialization() {
let vertex = Vertex3dNoTex2 {
x: 1.0,
y: 2.0,
z: 3.0,
nx: 0.0,
ny: 1.0,
nz: 0.0,
tu: 0.5,
tv: 0.5,
};
let bytes = vertex.as_vpx_bytes();
let deserialized_vertex = Vertex3dNoTex2::from_vpx_bytes(&bytes);
assert_eq!(vertex, deserialized_vertex);
}
}