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<u8>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Dir {
data: Vec<DirEntry>,
}
impl Dir {
pub fn as_bytes(&self) -> Vec<u8> {
let mut size = mem::size_of::<u32>();
for entry in &self.data {
size += mem::size_of::<u32>(); size += entry.path.as_bytes().len();
size += mem::size_of::<bool>() * 2; size += mem::size_of::<u32>(); size += entry.content.len();
}
let mut bytes = Vec::with_capacity(size);
bytes.extend((self.data.len() as u32).to_le_bytes().iter());
for entry in &self.data {
bytes.extend((entry.path.as_bytes().len() as u32).to_le_bytes().iter());
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
}
}
impl Dir {
#[allow(warnings)]
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let mut cursor = 0;
let len_prefix_size = mem::size_of::<u32>();
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<Vec<PathBuf>> {
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<DirEntry> = 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;
}
}