use std::{ fs, io, path::{Path, PathBuf}, }; fn main() { use std::mem; #[derive(Debug, Clone, PartialEq, Eq)] pub struct DirEntry { path: String, is_dir: bool, is_file: bool, content: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct Dir { data: Vec, } // Implement as_bytes() for Dir impl Dir { pub fn as_bytes(&self) -> Vec { // Calculate the total size of the serialized data let mut size = mem::size_of::(); // Size of the length prefix for entry in &self.data { size += mem::size_of::(); // Size of the entry size prefix size += entry.path.as_bytes().len(); size += mem::size_of::() * 2; // Sizes of is_dir and is_file fields size += mem::size_of::(); // Size of content size prefix size += entry.content.len(); } let mut bytes = Vec::with_capacity(size); // Write the length prefix bytes.extend((self.data.len() as u32).to_le_bytes().iter()); for entry in &self.data { // Write the size prefix for this entry bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter()); // Write the entry data bytes.extend(entry.path.as_bytes().iter()); bytes.extend(&[entry.is_dir as u8, entry.is_file as u8]); bytes.extend((entry.content.len() as u32).to_le_bytes().iter()); bytes.extend(entry.content.iter()); } bytes } } // Implement from_bytes() for Dir impl Dir { #[allow(warnings)] pub fn from_bytes(bytes: &[u8]) -> Option { let mut cursor = 0; let len_prefix_size = mem::size_of::(); if bytes.len() < len_prefix_size { return None; } let len = u32::from_le_bytes([ bytes[cursor], bytes[cursor + 1], bytes[cursor + 2], bytes[cursor + 3], ]) as usize; cursor += len_prefix_size; let mut data = Vec::with_capacity(len); for _ in 0..len { if bytes.len() < cursor + len_prefix_size { return None; } let entry_size = u32::from_le_bytes([ bytes[cursor], bytes[cursor + 1], bytes[cursor + 2], bytes[cursor + 3], ]) as usize; cursor += len_prefix_size; let end_pos = cursor + entry_size; if bytes.len() < end_pos { return None; } let path = String::from_utf8(bytes[cursor..end_pos].to_vec()).ok()?; cursor = end_pos; if bytes.len() < cursor + 2 { return None; } let is_dir = bytes[cursor] != 0; let is_file = bytes[cursor + 1] != 0; cursor += 2; if bytes.len() < cursor + len_prefix_size { return None; } let content_size = u32::from_le_bytes([ bytes[cursor], bytes[cursor + 1], bytes[cursor + 2], bytes[cursor + 3], ]) as usize; cursor += len_prefix_size; if bytes.len() < cursor + content_size { return None; } let content = bytes[cursor..cursor + content_size].to_vec(); cursor += content_size; data.push(DirEntry { path, is_dir, is_file, content, }); } Some(Dir { data }) } } pub fn walk_dir(path: impl ToString) -> io::Result> { let path = path.to_string(); let dir = Path::new(&path); let mut files = Vec::new(); for entry in fs::read_dir(dir)? { let entry = entry?; let newpath = entry.path(); if newpath.is_dir() { files.extend(walk_dir(&newpath.display())?); files.push(newpath); } else { files.push(newpath); } } Ok(files) } use std::env; let yok_path = match env::var("YOK_PATH") { Ok(value) => value, Err(_) => ".".to_string(), }; println!("cargo:rerun-if-env-changed={}", yok_path); println!("cargo:rerun-if-changed={}", yok_path); println!("cargo:rerun-if-changed=main.rs"); println!("cargo:rerun-if-changed=lib.rs"); let yok_path = std::path::Path::new(&yok_path); if yok_path.is_dir() { let mut res_dir: Vec = vec![]; let dir_list = walk_dir(yok_path.display()).expect("walk dir error"); for dir in dir_list { if dir.is_file() { res_dir.push(DirEntry { path: dir.strip_prefix(yok_path).unwrap().display().to_string(), is_dir: false, is_file: true, content: std::fs::read(dir).expect("read dir error"), }); } else if dir.is_dir() { res_dir.push(DirEntry { path: dir.strip_prefix(yok_path).unwrap().display().to_string(), is_dir: true, is_file: false, content: vec![], }); } } let all_dir: Dir = Dir { data: res_dir }; let all_dir_bytes = all_dir.as_bytes(); if let Ok(_) = std::fs::write(format!("../.yok"), all_dir_bytes){} } else { eprintln!("Environment variable 'YOK_PATH' not dir"); return; } }