Update dependencies and fix warnings

This commit is contained in:
Moritz Hölting 2024-04-25 14:15:35 +02:00
parent 19db26efa2
commit edcf80d389
12 changed files with 140 additions and 99 deletions

View File

@ -7,11 +7,12 @@ edition = "2021"
[features]
default = ["zip"]
serde = ["dep:serde"]
zip = ["dep:zip"]
[dependencies]
chksum-md5 = "0.0.0"
getset = "0.1.2"
serde = { version = "1.0.197", features = ["derive"] }
serde = { version = "1.0.197", optional = true, features = ["derive"] }
serde_json = "1.0.114"
zip = { version = "0.6.6", default-features = false, features = ["deflate", "time"], optional = true }
zip = { version = "1.1.1", default-features = false, features = ["deflate", "time"], optional = true }

View File

@ -1,13 +1,12 @@
use std::ops::{BitAnd, BitOr, Not};
use serde::{Deserialize, Serialize};
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
use super::Command;
#[allow(missing_docs)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub enum Execute {
Align(String, Box<Execute>),
Anchored(String, Box<Execute>),
@ -49,6 +48,7 @@ impl Execute {
.collect()
}
}
#[allow(clippy::too_many_lines)]
fn compile_internal(
&self,
prefix: String,
@ -170,7 +170,7 @@ impl Execute {
cond,
then.as_ref(),
el.as_deref(),
prefix,
&prefix,
options,
global_state,
function_state,
@ -233,15 +233,20 @@ fn compile_if_cond(
cond: &Condition,
then: &Execute,
el: Option<&Execute>,
prefix: String,
prefix: &str,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<(bool, String)> {
// TODO: fix conflicting data storage location when nesting if-else conditions
let str_then =
then.compile_internal(prefix.clone(), false, options, global_state, function_state);
let str_then = then.compile_internal(
prefix.to_string(),
false,
options,
global_state,
function_state,
);
let str_cond = cond.clone().compile(options, global_state, function_state);
let require_grouping = el.is_some() || str_then.len() > 1;
let then = if require_grouping {
@ -272,7 +277,7 @@ fn compile_if_cond(
"data modify storage shulkerbox:cond if_success set value true",
combine_conditions_commands(
str_cond.clone(),
vec![(
&[(
true,
"run data modify storage shulkerbox:cond if_success set value true".to_string(),
)],
@ -288,7 +293,7 @@ fn compile_if_cond(
} else {
str_cond
};
let then_commands = combine_conditions_commands(successful_cond, then);
let then_commands = combine_conditions_commands(successful_cond, &then);
let el_commands = el
.map(|el| {
let else_cond =
@ -301,7 +306,7 @@ fn compile_if_cond(
global_state,
function_state,
);
combine_conditions_commands(else_cond, el)
combine_conditions_commands(else_cond, &el)
})
.unwrap_or_default();
@ -323,7 +328,7 @@ fn compile_if_cond(
.chain(reset_success_storage)
.map(|(use_prefix, cmd)| {
let cmd = if use_prefix {
prefix.clone() + &cmd
prefix.to_string() + &cmd
} else {
cmd
};
@ -334,7 +339,7 @@ fn compile_if_cond(
fn combine_conditions_commands(
conditions: Vec<String>,
commands: Vec<(bool, String)>,
commands: &[(bool, String)],
) -> Vec<(bool, String)> {
conditions
.into_iter()
@ -352,7 +357,8 @@ fn combine_conditions_commands(
}
#[allow(missing_docs)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq)]
pub enum Condition {
Atom(String),
Not(Box<Condition>),
@ -361,11 +367,12 @@ pub enum Condition {
}
impl Condition {
/// Normalize the condition.
#[must_use]
pub fn normalize(&self) -> Self {
match self {
Self::Atom(_) => self.clone(),
Self::Not(c) => match *c.clone() {
Self::Atom(c) => Self::Not(Box::new(Self::Atom(c.clone()))),
Self::Atom(c) => Self::Not(Box::new(Self::Atom(c))),
Self::Not(c) => c.normalize(),
Self::And(c1, c2) => ((!*c1).normalize()) | ((!*c2).normalize()),
Self::Or(c1, c2) => ((!*c1).normalize()) & ((!*c2).normalize()),
@ -376,11 +383,12 @@ impl Condition {
}
/// Compile the condition into a list of strings.
#[allow(clippy::only_used_in_recursion)]
pub fn compile(
&self,
_options: &CompileOptions,
_global_state: &MutCompilerState,
_function_state: &FunctionCompilerState,
options: &CompileOptions,
global_state: &MutCompilerState,
function_state: &FunctionCompilerState,
) -> Vec<String> {
match self.normalize() {
Self::Atom(a) => vec!["if ".to_string() + &a],
@ -389,16 +397,16 @@ impl Condition {
_ => unreachable!("Cannot happen because of normalization"),
},
Self::And(c1, c2) => {
let c1 = c1.compile(_options, _global_state, _function_state);
let c2 = c2.compile(_options, _global_state, _function_state);
let c1 = c1.compile(options, global_state, function_state);
let c2 = c2.compile(options, global_state, function_state);
c1.into_iter()
.flat_map(|c1| c2.iter().map(move |c2| c1.clone() + " " + c2))
.collect()
}
Self::Or(c1, c2) => {
let mut c1 = c1.compile(_options, _global_state, _function_state);
let c2 = c2.compile(_options, _global_state, _function_state);
let mut c1 = c1.compile(options, global_state, function_state);
let c2 = c2.compile(options, global_state, function_state);
c1.extend(c2);
c1
}
@ -408,7 +416,7 @@ impl Condition {
impl From<&str> for Condition {
fn from(s: &str) -> Self {
Condition::Atom(s.to_string())
Self::Atom(s.to_string())
}
}
@ -416,21 +424,21 @@ impl Not for Condition {
type Output = Self;
fn not(self) -> Self {
Condition::Not(Box::new(self))
Self::Not(Box::new(self))
}
}
impl BitAnd for Condition {
type Output = Self;
fn bitand(self, rhs: Self) -> Self {
Condition::And(Box::new(self), Box::new(rhs))
Self::And(Box::new(self), Box::new(rhs))
}
}
impl BitOr for Condition {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Condition::Or(Box::new(self), Box::new(rhs))
Self::Or(Box::new(self), Box::new(rhs))
}
}
@ -470,11 +478,8 @@ mod tests {
);
assert_eq!(
(c1.clone() & c2.clone() | c3.clone() & c1.clone()).normalize(),
c1.clone() & c2.clone() | c3.clone() & c1.clone()
);
assert_eq!(
(!(c1.clone() | c2.clone())).normalize(),
!c1.clone() & !c2.clone()
c1.clone() & c2.clone() | c3 & c1.clone()
);
assert_eq!((!(c1.clone() | c2.clone())).normalize(), !c1 & !c2);
}
}

View File

@ -5,14 +5,14 @@ mod execute;
pub use execute::{Condition, Execute};
use chksum_md5 as md5;
use serde::{Deserialize, Serialize};
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
use super::Function;
/// Represents a command that can be included in a function.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub enum Command {
/// A command that is already formatted as a string.
Raw(String),
@ -28,6 +28,7 @@ pub enum Command {
impl Command {
/// Create a new raw command.
#[must_use]
pub fn raw(command: &str) -> Self {
Self::Raw(command.to_string())
}

View File

@ -1,7 +1,6 @@
//! Function struct and implementation
use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::{
util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
@ -11,7 +10,8 @@ use crate::{
use super::command::Command;
/// Function that can be called by a command
#[derive(Debug, Clone, Default, Serialize, Deserialize, Getters)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Default, Getters)]
pub struct Function {
commands: Vec<Command>,
/// Name of the function
@ -36,6 +36,7 @@ impl Function {
}
/// Get the commands of the function.
#[must_use]
pub fn get_commands(&self) -> &Vec<Command> {
&self.commands
}

View File

@ -7,7 +7,6 @@ pub mod tag;
pub use command::{Command, Condition, Execute};
pub use function::Function;
pub use namespace::Namespace;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, ops::RangeInclusive, path::Path, sync::Mutex};
@ -17,7 +16,8 @@ use crate::{
};
/// A Minecraft datapack.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Datapack {
// TODO: Support filter and overlays
name: String,
@ -32,6 +32,7 @@ pub struct Datapack {
impl Datapack {
/// Create a new Minecraft datapack.
#[must_use]
pub fn new(name: &str, pack_format: u8) -> Self {
Self {
name: name.to_string(),
@ -46,6 +47,7 @@ impl Datapack {
}
/// Set the description of the datapack.
#[must_use]
pub fn with_description(self, description: &str) -> Self {
Self {
description: description.to_string(),
@ -54,6 +56,7 @@ impl Datapack {
}
/// Set the supported pack formats of the datapack.
#[must_use]
pub fn with_supported_formats(self, supported_formats: RangeInclusive<u8>) -> Self {
Self {
supported_formats: Some(supported_formats),
@ -62,6 +65,9 @@ impl Datapack {
}
/// Set the custom files of the datapack.
///
/// # Errors
/// - If loading the directory fails
pub fn with_template_folder(self, path: &Path) -> std::io::Result<Self> {
let mut template = VFolder::try_from(path)?;
template.merge(self.custom_files);
@ -73,6 +79,7 @@ impl Datapack {
}
/// Get a namespace by name.
#[must_use]
pub fn namespace(&self, name: &str) -> Option<&Namespace> {
self.namespaces.get(name)
}
@ -100,6 +107,7 @@ impl Datapack {
}
/// Compile the pack into a virtual folder.
#[must_use]
pub fn compile(&self, options: &CompileOptions) -> VFolder {
let compiler_state = Mutex::new(CompilerState::default());
@ -152,7 +160,7 @@ fn generate_mcmeta(dp: &Datapack, _options: &CompileOptions, _state: &MutCompile
content["pack"]["supported_formats"] = serde_json::json!({
"min_inclusive": *supported_formats.start(),
"max_inclusive": *supported_formats.end()
})
});
}
VFile::Text(content.to_string())

View File

@ -1,11 +1,9 @@
//! Namespace of a datapack
use serde::{Deserialize, Serialize};
use crate::{
util::{
compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
extendable_queue::ExtendableQueue,
ExtendableQueue,
},
virtual_fs::VFolder,
};
@ -14,7 +12,8 @@ use super::{function::Function, tag::Tag};
use std::collections::{HashMap, VecDeque};
/// Namespace of a datapack
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Namespace {
name: String,
functions: HashMap<String, Function>,
@ -34,11 +33,13 @@ impl Namespace {
}
/// Get the name of the namespace.
#[must_use]
pub fn get_name(&self) -> &str {
&self.name
}
/// Get the main function of the namespace.
#[must_use]
pub fn get_main_function(&self) -> &Function {
&self.main_function
}
@ -48,16 +49,19 @@ impl Namespace {
}
/// Get the functions of the namespace.
#[must_use]
pub fn get_functions(&self) -> &HashMap<String, Function> {
&self.functions
}
/// Get the tags of the namespace.
#[must_use]
pub fn get_tags(&self) -> &HashMap<String, Tag> {
&self.tags
}
/// Get a function by name.
#[must_use]
pub fn function(&self, name: &str) -> Option<&Function> {
self.functions.get(name)
}
@ -94,7 +98,7 @@ impl Namespace {
while let Some((path, function)) = functions.next() {
let function_state = FunctionCompilerState::new(&path, &self.name, functions.clone());
root_folder.add_file(
&format!("functions/{}.mcfunction", path),
&format!("functions/{path}.mcfunction"),
function.compile(options, state, &function_state),
);
}
@ -102,7 +106,7 @@ impl Namespace {
// Compile tags
for (path, tag) in &self.tags {
let (tag_type, vfile) = tag.compile(options, state);
root_folder.add_file(&format!("tags/{}/{}.json", tag_type, path), vfile);
root_folder.add_file(&format!("tags/{tag_type}/{path}.json"), vfile);
}
root_folder

View File

@ -1,14 +1,13 @@
//! A tag for various types.
use serde::{Deserialize, Serialize};
use crate::{
util::compile::{CompileOptions, MutCompilerState},
virtual_fs::VFile,
};
/// A tag for various types.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct Tag {
r#type: TagType,
replace: bool,
@ -16,6 +15,7 @@ pub struct Tag {
}
impl Tag {
/// Create a new tag.
#[must_use]
pub fn new(r#type: TagType, replace: bool) -> Self {
Self {
r#type,
@ -48,7 +48,9 @@ impl Tag {
}
/// The type of a tag.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub enum TagType {
/// A tag for blocks.
Blocks,
@ -81,7 +83,9 @@ impl ToString for TagType {
}
/// The value of a tag.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub enum TagValue {
/// A simple value, either a resource location or an id of another tag.
Simple(String),
@ -100,6 +104,7 @@ impl From<&str> for TagValue {
}
impl TagValue {
/// Compile the tag value into a JSON value.
#[must_use]
pub fn compile(&self) -> serde_json::Value {
match self {
Self::Simple(value) => serde_json::Value::String(value.clone()),

View File

@ -1,14 +1,15 @@
//! Shulkerbox is a library for creating Minecraft data packs.
#![warn(
missing_docs,
#![deny(
unsafe_code,
missing_debug_implementations,
nonstandard_style,
clippy::complexity,
clippy::style,
clippy::suspicious
missing_copy_implementations,
clippy::nursery,
rustdoc::broken_intra_doc_links,
clippy::missing_errors_doc
)]
#![deny(unsafe_code)]
#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::missing_panics_doc, clippy::missing_const_for_fn)]
pub mod datapack;
pub mod util;

View File

@ -3,14 +3,15 @@
use std::{cell::Cell, sync::Mutex};
use getset::Getters;
use serde::{Deserialize, Serialize};
use crate::datapack::Function;
use super::extendable_queue::ExtendableQueue;
/// Compile options for the compiler.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(missing_copy_implementations, clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub struct CompileOptions {
/// Whether to compile in debug mode.
pub debug: bool,
@ -23,7 +24,9 @@ impl Default for CompileOptions {
}
/// State of the compiler that can change during compilation.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[allow(missing_copy_implementations)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Default)]
pub struct CompilerState {}
/// Mutex for the compiler state.
pub type MutCompilerState = Mutex<CompilerState>;
@ -48,6 +51,7 @@ type FunctionQueue = ExtendableQueue<(String, Function)>;
impl FunctionCompilerState {
/// Create a new function compiler state.
#[must_use]
pub fn new(path: &str, namespace: &str, functions: FunctionQueue) -> Self {
Self {
generated_functions: Cell::new(0),

View File

@ -37,11 +37,13 @@ impl<T> ExtendableQueue<T> {
}
/// Get the queue.
#[must_use]
pub fn get(&self) -> &Arc<RwLock<VecDeque<T>>> {
&self.queue
}
/// Get a weak reference to the queue.
#[must_use]
pub fn get_weak(&self) -> Weak<RwLock<VecDeque<T>>> {
Arc::downgrade(&self.queue)
}
@ -52,16 +54,19 @@ impl<T> ExtendableQueue<T> {
}
/// Get the length of the queue.
#[must_use]
pub fn len(&self) -> usize {
self.queue.read().unwrap().len()
}
/// Check if the queue is empty.
#[must_use]
pub fn is_empty(&self) -> bool {
self.queue.read().unwrap().is_empty()
}
/// Get and remove the next item without needing mutable access.
#[must_use]
pub fn pop_front(&self) -> Option<T> {
self.queue.write().unwrap().pop_front()
}

View File

@ -1,4 +1,7 @@
//! Utility functions for the Shulkerbox project.
pub mod compile;
pub mod extendable_queue;
mod extendable_queue;
#[doc(inline)]
pub use extendable_queue::ExtendableQueue;

View File

@ -2,49 +2,51 @@
use std::{collections::HashMap, fs, io, path::Path};
use serde::{Deserialize, Serialize};
#[cfg(feature = "zip")]
use zip::ZipWriter;
/// Folder representation in virtual file system
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Default, Clone)]
pub struct VFolder {
folders: HashMap<String, VFolder>,
files: HashMap<String, VFile>,
}
impl VFolder {
/// Create a new, empty virtual folder.
pub fn new() -> VFolder {
VFolder {
#[must_use]
pub fn new() -> Self {
Self {
folders: HashMap::new(),
files: HashMap::new(),
}
}
/// Get all direct subfolders in the folder.
pub fn get_folders(&self) -> &HashMap<String, VFolder> {
#[must_use]
pub fn get_folders(&self) -> &HashMap<String, Self> {
&self.folders
}
/// Get all direct files in the folder.
#[must_use]
pub fn get_files(&self) -> &HashMap<String, VFile> {
&self.files
}
/// Recursively add a new folder to the folder.
pub fn add_folder(&mut self, path: &str) {
self.add_existing_folder(path, VFolder::new());
self.add_existing_folder(path, Self::new());
}
/// Recursively add an existing folder to the folder.
pub fn add_existing_folder(&mut self, path: &str, folder: VFolder) {
pub fn add_existing_folder(&mut self, path: &str, folder: Self) {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
if let Some(subfolder) = self.get_folder_mut(head) {
subfolder.add_folder(tail);
} else {
let mut new_folder = VFolder::new();
let mut new_folder = Self::new();
new_folder.add_folder(tail);
self.add_existing_folder(head, new_folder);
}
@ -56,13 +58,12 @@ impl VFolder {
pub fn add_file(&mut self, path: &str, file: VFile) {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
if let Some(subfolder) = self.get_folder_mut(head) {
subfolder.add_file(tail, file);
} else {
let mut new_folder = VFolder::new();
let mut new_folder = Self::new();
new_folder.add_file(tail, file);
self.add_existing_folder(head, new_folder);
}
@ -72,11 +73,11 @@ impl VFolder {
}
/// Recursively get a subfolder by path.
pub fn get_folder(&self, path: &str) -> Option<&VFolder> {
#[must_use]
pub fn get_folder(&self, path: &str) -> Option<&Self> {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
self.folders.get(head)?.get_folder(tail)
} else {
@ -84,11 +85,10 @@ impl VFolder {
}
}
/// Recursively get a mutable subfolder by path.
pub fn get_folder_mut(&mut self, path: &str) -> Option<&mut VFolder> {
pub fn get_folder_mut(&mut self, path: &str) -> Option<&mut Self> {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
self.folders.get_mut(head)?.get_folder_mut(tail)
} else {
@ -96,11 +96,11 @@ impl VFolder {
}
}
/// Recursively get a file by path.
#[must_use]
pub fn get_file(&self, path: &str) -> Option<&VFile> {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
self.folders.get(head)?.get_file(tail)
} else {
@ -111,8 +111,7 @@ impl VFolder {
pub fn get_file_mut(&mut self, path: &str) -> Option<&mut VFile> {
let (head, tail) = path
.split_once('/')
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
.unwrap_or((path, None));
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
if let Some(tail) = tail {
self.folders.get_mut(head)?.get_file_mut(tail)
} else {
@ -121,6 +120,9 @@ impl VFolder {
}
/// Place the folder and its contents on the file system.
///
/// # Errors
/// - If the folder cannot be written
pub fn place(&self, path: &Path) -> io::Result<()> {
fs::create_dir_all(path)?;
for (name, folder) in &self.folders {
@ -141,6 +143,9 @@ impl VFolder {
#[cfg(feature = "zip")]
/// Zip the folder and its contents into a zip archive.
///
/// # Errors
/// - If the zip archive cannot be written
pub fn zip(&self, path: &Path) -> io::Result<()> {
use io::Write;
@ -149,7 +154,7 @@ impl VFolder {
let virtual_files = self.flatten();
for (path, file) in virtual_files {
writer.start_file(path, Default::default())?;
writer.start_file(path, zip::write::SimpleFileOptions::default())?;
match file {
VFile::Text(text) => {
writer.write_all(text.as_bytes())?;
@ -166,6 +171,7 @@ impl VFolder {
}
/// Flatten the folder and its contents into a list of files with full paths.
#[must_use]
pub fn flatten(&self) -> Vec<(String, &VFile)> {
let mut files = self
.files
@ -177,7 +183,7 @@ impl VFolder {
let sub_files = folder
.flatten()
.into_iter()
.map(|(path, file)| (format!("{}/{}", name, path), file))
.map(|(path, file)| (format!("{name}/{path}"), file))
.collect::<Vec<_>>();
files.extend(sub_files);
}
@ -204,19 +210,15 @@ impl TryFrom<&Path> for VFolder {
type Error = io::Error;
fn try_from(value: &Path) -> Result<Self, Self::Error> {
let mut root_vfolder = VFolder::new();
let root_folder = fs::read_dir(value)?;
for dir_entry in root_folder {
let mut root_vfolder = Self::new();
let fs_root_folder = fs::read_dir(value)?;
for dir_entry in fs_root_folder {
let dir_entry = dir_entry?;
let path = dir_entry.path();
let name = dir_entry
.file_name()
.into_string()
.map(Some)
.unwrap_or_default();
let name = dir_entry.file_name().into_string().ok();
if let Some(name) = name {
if path.is_dir() {
root_vfolder.add_existing_folder(&name, VFolder::try_from(path.as_path())?);
root_vfolder.add_existing_folder(&name, Self::try_from(path.as_path())?);
} else if path.is_file() {
let data = fs::read(path)?;
root_vfolder.add_file(&name, VFile::Binary(data));
@ -236,7 +238,8 @@ impl TryFrom<&Path> for VFolder {
}
/// File representation in virtual file system
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone)]
pub enum VFile {
/// Text file
Text(String),
@ -246,17 +249,17 @@ pub enum VFile {
impl From<String> for VFile {
fn from(value: String) -> Self {
VFile::Text(value)
Self::Text(value)
}
}
impl From<&str> for VFile {
fn from(value: &str) -> Self {
VFile::Text(value.to_string())
Self::Text(value.to_string())
}
}
impl Default for VFile {
fn default() -> Self {
VFile::Text(String::new())
Self::Text(String::new())
}
}