Update dependencies and fix warnings
This commit is contained in:
parent
19db26efa2
commit
edcf80d389
|
@ -7,11 +7,12 @@ edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["zip"]
|
default = ["zip"]
|
||||||
|
serde = ["dep:serde"]
|
||||||
zip = ["dep:zip"]
|
zip = ["dep:zip"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chksum-md5 = "0.0.0"
|
chksum-md5 = "0.0.0"
|
||||||
getset = "0.1.2"
|
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"
|
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 }
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use std::ops::{BitAnd, BitOr, Not};
|
use std::ops::{BitAnd, BitOr, Not};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
|
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
|
||||||
|
|
||||||
use super::Command;
|
use super::Command;
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub enum Execute {
|
pub enum Execute {
|
||||||
Align(String, Box<Execute>),
|
Align(String, Box<Execute>),
|
||||||
Anchored(String, Box<Execute>),
|
Anchored(String, Box<Execute>),
|
||||||
|
@ -49,6 +48,7 @@ impl Execute {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn compile_internal(
|
fn compile_internal(
|
||||||
&self,
|
&self,
|
||||||
prefix: String,
|
prefix: String,
|
||||||
|
@ -170,7 +170,7 @@ impl Execute {
|
||||||
cond,
|
cond,
|
||||||
then.as_ref(),
|
then.as_ref(),
|
||||||
el.as_deref(),
|
el.as_deref(),
|
||||||
prefix,
|
&prefix,
|
||||||
options,
|
options,
|
||||||
global_state,
|
global_state,
|
||||||
function_state,
|
function_state,
|
||||||
|
@ -233,15 +233,20 @@ fn compile_if_cond(
|
||||||
cond: &Condition,
|
cond: &Condition,
|
||||||
then: &Execute,
|
then: &Execute,
|
||||||
el: Option<&Execute>,
|
el: Option<&Execute>,
|
||||||
prefix: String,
|
prefix: &str,
|
||||||
options: &CompileOptions,
|
options: &CompileOptions,
|
||||||
global_state: &MutCompilerState,
|
global_state: &MutCompilerState,
|
||||||
function_state: &FunctionCompilerState,
|
function_state: &FunctionCompilerState,
|
||||||
) -> Vec<(bool, String)> {
|
) -> Vec<(bool, String)> {
|
||||||
// TODO: fix conflicting data storage location when nesting if-else conditions
|
// TODO: fix conflicting data storage location when nesting if-else conditions
|
||||||
|
|
||||||
let str_then =
|
let str_then = then.compile_internal(
|
||||||
then.compile_internal(prefix.clone(), false, options, global_state, function_state);
|
prefix.to_string(),
|
||||||
|
false,
|
||||||
|
options,
|
||||||
|
global_state,
|
||||||
|
function_state,
|
||||||
|
);
|
||||||
let str_cond = cond.clone().compile(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 require_grouping = el.is_some() || str_then.len() > 1;
|
||||||
let then = if require_grouping {
|
let then = if require_grouping {
|
||||||
|
@ -272,7 +277,7 @@ fn compile_if_cond(
|
||||||
"data modify storage shulkerbox:cond if_success set value true",
|
"data modify storage shulkerbox:cond if_success set value true",
|
||||||
combine_conditions_commands(
|
combine_conditions_commands(
|
||||||
str_cond.clone(),
|
str_cond.clone(),
|
||||||
vec![(
|
&[(
|
||||||
true,
|
true,
|
||||||
"run data modify storage shulkerbox:cond if_success set value true".to_string(),
|
"run data modify storage shulkerbox:cond if_success set value true".to_string(),
|
||||||
)],
|
)],
|
||||||
|
@ -288,7 +293,7 @@ fn compile_if_cond(
|
||||||
} else {
|
} else {
|
||||||
str_cond
|
str_cond
|
||||||
};
|
};
|
||||||
let then_commands = combine_conditions_commands(successful_cond, then);
|
let then_commands = combine_conditions_commands(successful_cond, &then);
|
||||||
let el_commands = el
|
let el_commands = el
|
||||||
.map(|el| {
|
.map(|el| {
|
||||||
let else_cond =
|
let else_cond =
|
||||||
|
@ -301,7 +306,7 @@ fn compile_if_cond(
|
||||||
global_state,
|
global_state,
|
||||||
function_state,
|
function_state,
|
||||||
);
|
);
|
||||||
combine_conditions_commands(else_cond, el)
|
combine_conditions_commands(else_cond, &el)
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -323,7 +328,7 @@ fn compile_if_cond(
|
||||||
.chain(reset_success_storage)
|
.chain(reset_success_storage)
|
||||||
.map(|(use_prefix, cmd)| {
|
.map(|(use_prefix, cmd)| {
|
||||||
let cmd = if use_prefix {
|
let cmd = if use_prefix {
|
||||||
prefix.clone() + &cmd
|
prefix.to_string() + &cmd
|
||||||
} else {
|
} else {
|
||||||
cmd
|
cmd
|
||||||
};
|
};
|
||||||
|
@ -334,7 +339,7 @@ fn compile_if_cond(
|
||||||
|
|
||||||
fn combine_conditions_commands(
|
fn combine_conditions_commands(
|
||||||
conditions: Vec<String>,
|
conditions: Vec<String>,
|
||||||
commands: Vec<(bool, String)>,
|
commands: &[(bool, String)],
|
||||||
) -> Vec<(bool, String)> {
|
) -> Vec<(bool, String)> {
|
||||||
conditions
|
conditions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -352,7 +357,8 @@ fn combine_conditions_commands(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[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 {
|
pub enum Condition {
|
||||||
Atom(String),
|
Atom(String),
|
||||||
Not(Box<Condition>),
|
Not(Box<Condition>),
|
||||||
|
@ -361,11 +367,12 @@ pub enum Condition {
|
||||||
}
|
}
|
||||||
impl Condition {
|
impl Condition {
|
||||||
/// Normalize the condition.
|
/// Normalize the condition.
|
||||||
|
#[must_use]
|
||||||
pub fn normalize(&self) -> Self {
|
pub fn normalize(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Atom(_) => self.clone(),
|
Self::Atom(_) => self.clone(),
|
||||||
Self::Not(c) => match *c.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::Not(c) => c.normalize(),
|
||||||
Self::And(c1, c2) => ((!*c1).normalize()) | ((!*c2).normalize()),
|
Self::And(c1, c2) => ((!*c1).normalize()) | ((!*c2).normalize()),
|
||||||
Self::Or(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.
|
/// Compile the condition into a list of strings.
|
||||||
|
#[allow(clippy::only_used_in_recursion)]
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
&self,
|
&self,
|
||||||
_options: &CompileOptions,
|
options: &CompileOptions,
|
||||||
_global_state: &MutCompilerState,
|
global_state: &MutCompilerState,
|
||||||
_function_state: &FunctionCompilerState,
|
function_state: &FunctionCompilerState,
|
||||||
) -> Vec<String> {
|
) -> Vec<String> {
|
||||||
match self.normalize() {
|
match self.normalize() {
|
||||||
Self::Atom(a) => vec!["if ".to_string() + &a],
|
Self::Atom(a) => vec!["if ".to_string() + &a],
|
||||||
|
@ -389,16 +397,16 @@ impl Condition {
|
||||||
_ => unreachable!("Cannot happen because of normalization"),
|
_ => unreachable!("Cannot happen because of normalization"),
|
||||||
},
|
},
|
||||||
Self::And(c1, c2) => {
|
Self::And(c1, c2) => {
|
||||||
let c1 = c1.compile(_options, _global_state, _function_state);
|
let c1 = c1.compile(options, global_state, function_state);
|
||||||
let c2 = c2.compile(_options, _global_state, _function_state);
|
let c2 = c2.compile(options, global_state, function_state);
|
||||||
|
|
||||||
c1.into_iter()
|
c1.into_iter()
|
||||||
.flat_map(|c1| c2.iter().map(move |c2| c1.clone() + " " + c2))
|
.flat_map(|c1| c2.iter().map(move |c2| c1.clone() + " " + c2))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
Self::Or(c1, c2) => {
|
Self::Or(c1, c2) => {
|
||||||
let mut c1 = c1.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);
|
let c2 = c2.compile(options, global_state, function_state);
|
||||||
c1.extend(c2);
|
c1.extend(c2);
|
||||||
c1
|
c1
|
||||||
}
|
}
|
||||||
|
@ -408,7 +416,7 @@ impl Condition {
|
||||||
|
|
||||||
impl From<&str> for Condition {
|
impl From<&str> for Condition {
|
||||||
fn from(s: &str) -> Self {
|
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;
|
type Output = Self;
|
||||||
|
|
||||||
fn not(self) -> Self {
|
fn not(self) -> Self {
|
||||||
Condition::Not(Box::new(self))
|
Self::Not(Box::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl BitAnd for Condition {
|
impl BitAnd for Condition {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn bitand(self, rhs: Self) -> 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 {
|
impl BitOr for Condition {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn bitor(self, rhs: Self) -> 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!(
|
assert_eq!(
|
||||||
(c1.clone() & c2.clone() | c3.clone() & c1.clone()).normalize(),
|
(c1.clone() & c2.clone() | c3.clone() & c1.clone()).normalize(),
|
||||||
c1.clone() & c2.clone() | c3.clone() & c1.clone()
|
c1.clone() & c2.clone() | c3 & c1.clone()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
(!(c1.clone() | c2.clone())).normalize(),
|
|
||||||
!c1.clone() & !c2.clone()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!((!(c1.clone() | c2.clone())).normalize(), !c1 & !c2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ mod execute;
|
||||||
pub use execute::{Condition, Execute};
|
pub use execute::{Condition, Execute};
|
||||||
|
|
||||||
use chksum_md5 as md5;
|
use chksum_md5 as md5;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
|
use crate::util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState};
|
||||||
|
|
||||||
use super::Function;
|
use super::Function;
|
||||||
|
|
||||||
/// Represents a command that can be included in a 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 {
|
pub enum Command {
|
||||||
/// A command that is already formatted as a string.
|
/// A command that is already formatted as a string.
|
||||||
Raw(String),
|
Raw(String),
|
||||||
|
@ -28,6 +28,7 @@ pub enum Command {
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
/// Create a new raw command.
|
/// Create a new raw command.
|
||||||
|
#[must_use]
|
||||||
pub fn raw(command: &str) -> Self {
|
pub fn raw(command: &str) -> Self {
|
||||||
Self::Raw(command.to_string())
|
Self::Raw(command.to_string())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Function struct and implementation
|
//! Function struct and implementation
|
||||||
|
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
|
util::compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
|
||||||
|
@ -11,7 +10,8 @@ use crate::{
|
||||||
use super::command::Command;
|
use super::command::Command;
|
||||||
|
|
||||||
/// Function that can be called by a 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 {
|
pub struct Function {
|
||||||
commands: Vec<Command>,
|
commands: Vec<Command>,
|
||||||
/// Name of the function
|
/// Name of the function
|
||||||
|
@ -36,6 +36,7 @@ impl Function {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the commands of the function.
|
/// Get the commands of the function.
|
||||||
|
#[must_use]
|
||||||
pub fn get_commands(&self) -> &Vec<Command> {
|
pub fn get_commands(&self) -> &Vec<Command> {
|
||||||
&self.commands
|
&self.commands
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ pub mod tag;
|
||||||
pub use command::{Command, Condition, Execute};
|
pub use command::{Command, Condition, Execute};
|
||||||
pub use function::Function;
|
pub use function::Function;
|
||||||
pub use namespace::Namespace;
|
pub use namespace::Namespace;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use std::{collections::HashMap, ops::RangeInclusive, path::Path, sync::Mutex};
|
use std::{collections::HashMap, ops::RangeInclusive, path::Path, sync::Mutex};
|
||||||
|
|
||||||
|
@ -17,7 +16,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A Minecraft datapack.
|
/// A Minecraft datapack.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Datapack {
|
pub struct Datapack {
|
||||||
// TODO: Support filter and overlays
|
// TODO: Support filter and overlays
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -32,6 +32,7 @@ pub struct Datapack {
|
||||||
|
|
||||||
impl Datapack {
|
impl Datapack {
|
||||||
/// Create a new Minecraft datapack.
|
/// Create a new Minecraft datapack.
|
||||||
|
#[must_use]
|
||||||
pub fn new(name: &str, pack_format: u8) -> Self {
|
pub fn new(name: &str, pack_format: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
@ -46,6 +47,7 @@ impl Datapack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the description of the datapack.
|
/// Set the description of the datapack.
|
||||||
|
#[must_use]
|
||||||
pub fn with_description(self, description: &str) -> Self {
|
pub fn with_description(self, description: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
description: description.to_string(),
|
description: description.to_string(),
|
||||||
|
@ -54,6 +56,7 @@ impl Datapack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the supported pack formats of the datapack.
|
/// Set the supported pack formats of the datapack.
|
||||||
|
#[must_use]
|
||||||
pub fn with_supported_formats(self, supported_formats: RangeInclusive<u8>) -> Self {
|
pub fn with_supported_formats(self, supported_formats: RangeInclusive<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
supported_formats: Some(supported_formats),
|
supported_formats: Some(supported_formats),
|
||||||
|
@ -62,6 +65,9 @@ impl Datapack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the custom files of the 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> {
|
pub fn with_template_folder(self, path: &Path) -> std::io::Result<Self> {
|
||||||
let mut template = VFolder::try_from(path)?;
|
let mut template = VFolder::try_from(path)?;
|
||||||
template.merge(self.custom_files);
|
template.merge(self.custom_files);
|
||||||
|
@ -73,6 +79,7 @@ impl Datapack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a namespace by name.
|
/// Get a namespace by name.
|
||||||
|
#[must_use]
|
||||||
pub fn namespace(&self, name: &str) -> Option<&Namespace> {
|
pub fn namespace(&self, name: &str) -> Option<&Namespace> {
|
||||||
self.namespaces.get(name)
|
self.namespaces.get(name)
|
||||||
}
|
}
|
||||||
|
@ -100,6 +107,7 @@ impl Datapack {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the pack into a virtual folder.
|
/// Compile the pack into a virtual folder.
|
||||||
|
#[must_use]
|
||||||
pub fn compile(&self, options: &CompileOptions) -> VFolder {
|
pub fn compile(&self, options: &CompileOptions) -> VFolder {
|
||||||
let compiler_state = Mutex::new(CompilerState::default());
|
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!({
|
content["pack"]["supported_formats"] = serde_json::json!({
|
||||||
"min_inclusive": *supported_formats.start(),
|
"min_inclusive": *supported_formats.start(),
|
||||||
"max_inclusive": *supported_formats.end()
|
"max_inclusive": *supported_formats.end()
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
VFile::Text(content.to_string())
|
VFile::Text(content.to_string())
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
//! Namespace of a datapack
|
//! Namespace of a datapack
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::{
|
util::{
|
||||||
compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
|
compile::{CompileOptions, FunctionCompilerState, MutCompilerState},
|
||||||
extendable_queue::ExtendableQueue,
|
ExtendableQueue,
|
||||||
},
|
},
|
||||||
virtual_fs::VFolder,
|
virtual_fs::VFolder,
|
||||||
};
|
};
|
||||||
|
@ -14,7 +12,8 @@ use super::{function::Function, tag::Tag};
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
/// Namespace of a datapack
|
/// Namespace of a datapack
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct Namespace {
|
pub struct Namespace {
|
||||||
name: String,
|
name: String,
|
||||||
functions: HashMap<String, Function>,
|
functions: HashMap<String, Function>,
|
||||||
|
@ -34,11 +33,13 @@ impl Namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the name of the namespace.
|
/// Get the name of the namespace.
|
||||||
|
#[must_use]
|
||||||
pub fn get_name(&self) -> &str {
|
pub fn get_name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the main function of the namespace.
|
/// Get the main function of the namespace.
|
||||||
|
#[must_use]
|
||||||
pub fn get_main_function(&self) -> &Function {
|
pub fn get_main_function(&self) -> &Function {
|
||||||
&self.main_function
|
&self.main_function
|
||||||
}
|
}
|
||||||
|
@ -48,16 +49,19 @@ impl Namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the functions of the namespace.
|
/// Get the functions of the namespace.
|
||||||
|
#[must_use]
|
||||||
pub fn get_functions(&self) -> &HashMap<String, Function> {
|
pub fn get_functions(&self) -> &HashMap<String, Function> {
|
||||||
&self.functions
|
&self.functions
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tags of the namespace.
|
/// Get the tags of the namespace.
|
||||||
|
#[must_use]
|
||||||
pub fn get_tags(&self) -> &HashMap<String, Tag> {
|
pub fn get_tags(&self) -> &HashMap<String, Tag> {
|
||||||
&self.tags
|
&self.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a function by name.
|
/// Get a function by name.
|
||||||
|
#[must_use]
|
||||||
pub fn function(&self, name: &str) -> Option<&Function> {
|
pub fn function(&self, name: &str) -> Option<&Function> {
|
||||||
self.functions.get(name)
|
self.functions.get(name)
|
||||||
}
|
}
|
||||||
|
@ -94,7 +98,7 @@ impl Namespace {
|
||||||
while let Some((path, function)) = functions.next() {
|
while let Some((path, function)) = functions.next() {
|
||||||
let function_state = FunctionCompilerState::new(&path, &self.name, functions.clone());
|
let function_state = FunctionCompilerState::new(&path, &self.name, functions.clone());
|
||||||
root_folder.add_file(
|
root_folder.add_file(
|
||||||
&format!("functions/{}.mcfunction", path),
|
&format!("functions/{path}.mcfunction"),
|
||||||
function.compile(options, state, &function_state),
|
function.compile(options, state, &function_state),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +106,7 @@ impl Namespace {
|
||||||
// Compile tags
|
// Compile tags
|
||||||
for (path, tag) in &self.tags {
|
for (path, tag) in &self.tags {
|
||||||
let (tag_type, vfile) = tag.compile(options, state);
|
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
|
root_folder
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
//! A tag for various types.
|
//! A tag for various types.
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::compile::{CompileOptions, MutCompilerState},
|
util::compile::{CompileOptions, MutCompilerState},
|
||||||
virtual_fs::VFile,
|
virtual_fs::VFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A tag for various types.
|
/// 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 {
|
pub struct Tag {
|
||||||
r#type: TagType,
|
r#type: TagType,
|
||||||
replace: bool,
|
replace: bool,
|
||||||
|
@ -16,6 +15,7 @@ pub struct Tag {
|
||||||
}
|
}
|
||||||
impl Tag {
|
impl Tag {
|
||||||
/// Create a new tag.
|
/// Create a new tag.
|
||||||
|
#[must_use]
|
||||||
pub fn new(r#type: TagType, replace: bool) -> Self {
|
pub fn new(r#type: TagType, replace: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
r#type,
|
r#type,
|
||||||
|
@ -48,7 +48,9 @@ impl Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of a 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 {
|
pub enum TagType {
|
||||||
/// A tag for blocks.
|
/// A tag for blocks.
|
||||||
Blocks,
|
Blocks,
|
||||||
|
@ -81,7 +83,9 @@ impl ToString for TagType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The value of a tag.
|
/// 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 {
|
pub enum TagValue {
|
||||||
/// A simple value, either a resource location or an id of another tag.
|
/// A simple value, either a resource location or an id of another tag.
|
||||||
Simple(String),
|
Simple(String),
|
||||||
|
@ -100,6 +104,7 @@ impl From<&str> for TagValue {
|
||||||
}
|
}
|
||||||
impl TagValue {
|
impl TagValue {
|
||||||
/// Compile the tag value into a JSON value.
|
/// Compile the tag value into a JSON value.
|
||||||
|
#[must_use]
|
||||||
pub fn compile(&self) -> serde_json::Value {
|
pub fn compile(&self) -> serde_json::Value {
|
||||||
match self {
|
match self {
|
||||||
Self::Simple(value) => serde_json::Value::String(value.clone()),
|
Self::Simple(value) => serde_json::Value::String(value.clone()),
|
||||||
|
|
15
src/lib.rs
15
src/lib.rs
|
@ -1,14 +1,15 @@
|
||||||
//! Shulkerbox is a library for creating Minecraft data packs.
|
//! Shulkerbox is a library for creating Minecraft data packs.
|
||||||
|
|
||||||
#![warn(
|
#![deny(
|
||||||
missing_docs,
|
unsafe_code,
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
nonstandard_style,
|
missing_copy_implementations,
|
||||||
clippy::complexity,
|
clippy::nursery,
|
||||||
clippy::style,
|
rustdoc::broken_intra_doc_links,
|
||||||
clippy::suspicious
|
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 datapack;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
|
@ -3,14 +3,15 @@
|
||||||
use std::{cell::Cell, sync::Mutex};
|
use std::{cell::Cell, sync::Mutex};
|
||||||
|
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::datapack::Function;
|
use crate::datapack::Function;
|
||||||
|
|
||||||
use super::extendable_queue::ExtendableQueue;
|
use super::extendable_queue::ExtendableQueue;
|
||||||
|
|
||||||
/// Compile options for the compiler.
|
/// 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 {
|
pub struct CompileOptions {
|
||||||
/// Whether to compile in debug mode.
|
/// Whether to compile in debug mode.
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
|
@ -23,7 +24,9 @@ impl Default for CompileOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State of the compiler that can change during compilation.
|
/// 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 {}
|
pub struct CompilerState {}
|
||||||
/// Mutex for the compiler state.
|
/// Mutex for the compiler state.
|
||||||
pub type MutCompilerState = Mutex<CompilerState>;
|
pub type MutCompilerState = Mutex<CompilerState>;
|
||||||
|
@ -48,6 +51,7 @@ type FunctionQueue = ExtendableQueue<(String, Function)>;
|
||||||
|
|
||||||
impl FunctionCompilerState {
|
impl FunctionCompilerState {
|
||||||
/// Create a new function compiler state.
|
/// Create a new function compiler state.
|
||||||
|
#[must_use]
|
||||||
pub fn new(path: &str, namespace: &str, functions: FunctionQueue) -> Self {
|
pub fn new(path: &str, namespace: &str, functions: FunctionQueue) -> Self {
|
||||||
Self {
|
Self {
|
||||||
generated_functions: Cell::new(0),
|
generated_functions: Cell::new(0),
|
||||||
|
|
|
@ -37,11 +37,13 @@ impl<T> ExtendableQueue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the queue.
|
/// Get the queue.
|
||||||
|
#[must_use]
|
||||||
pub fn get(&self) -> &Arc<RwLock<VecDeque<T>>> {
|
pub fn get(&self) -> &Arc<RwLock<VecDeque<T>>> {
|
||||||
&self.queue
|
&self.queue
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a weak reference to the queue.
|
/// Get a weak reference to the queue.
|
||||||
|
#[must_use]
|
||||||
pub fn get_weak(&self) -> Weak<RwLock<VecDeque<T>>> {
|
pub fn get_weak(&self) -> Weak<RwLock<VecDeque<T>>> {
|
||||||
Arc::downgrade(&self.queue)
|
Arc::downgrade(&self.queue)
|
||||||
}
|
}
|
||||||
|
@ -52,16 +54,19 @@ impl<T> ExtendableQueue<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the length of the queue.
|
/// Get the length of the queue.
|
||||||
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.queue.read().unwrap().len()
|
self.queue.read().unwrap().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the queue is empty.
|
/// Check if the queue is empty.
|
||||||
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.queue.read().unwrap().is_empty()
|
self.queue.read().unwrap().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get and remove the next item without needing mutable access.
|
/// Get and remove the next item without needing mutable access.
|
||||||
|
#[must_use]
|
||||||
pub fn pop_front(&self) -> Option<T> {
|
pub fn pop_front(&self) -> Option<T> {
|
||||||
self.queue.write().unwrap().pop_front()
|
self.queue.write().unwrap().pop_front()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
//! Utility functions for the Shulkerbox project.
|
//! Utility functions for the Shulkerbox project.
|
||||||
|
|
||||||
pub mod compile;
|
pub mod compile;
|
||||||
pub mod extendable_queue;
|
mod extendable_queue;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use extendable_queue::ExtendableQueue;
|
||||||
|
|
|
@ -2,49 +2,51 @@
|
||||||
|
|
||||||
use std::{collections::HashMap, fs, io, path::Path};
|
use std::{collections::HashMap, fs, io, path::Path};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
#[cfg(feature = "zip")]
|
#[cfg(feature = "zip")]
|
||||||
use zip::ZipWriter;
|
use zip::ZipWriter;
|
||||||
|
|
||||||
/// Folder representation in virtual file system
|
/// 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 {
|
pub struct VFolder {
|
||||||
folders: HashMap<String, VFolder>,
|
folders: HashMap<String, VFolder>,
|
||||||
files: HashMap<String, VFile>,
|
files: HashMap<String, VFile>,
|
||||||
}
|
}
|
||||||
impl VFolder {
|
impl VFolder {
|
||||||
/// Create a new, empty virtual folder.
|
/// Create a new, empty virtual folder.
|
||||||
pub fn new() -> VFolder {
|
#[must_use]
|
||||||
VFolder {
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
folders: HashMap::new(),
|
folders: HashMap::new(),
|
||||||
files: HashMap::new(),
|
files: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all direct subfolders in the folder.
|
/// 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
|
&self.folders
|
||||||
}
|
}
|
||||||
/// Get all direct files in the folder.
|
/// Get all direct files in the folder.
|
||||||
|
#[must_use]
|
||||||
pub fn get_files(&self) -> &HashMap<String, VFile> {
|
pub fn get_files(&self) -> &HashMap<String, VFile> {
|
||||||
&self.files
|
&self.files
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively add a new folder to the folder.
|
/// Recursively add a new folder to the folder.
|
||||||
pub fn add_folder(&mut self, path: &str) {
|
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.
|
/// 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
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
if let Some(subfolder) = self.get_folder_mut(head) {
|
if let Some(subfolder) = self.get_folder_mut(head) {
|
||||||
subfolder.add_folder(tail);
|
subfolder.add_folder(tail);
|
||||||
} else {
|
} else {
|
||||||
let mut new_folder = VFolder::new();
|
let mut new_folder = Self::new();
|
||||||
new_folder.add_folder(tail);
|
new_folder.add_folder(tail);
|
||||||
self.add_existing_folder(head, new_folder);
|
self.add_existing_folder(head, new_folder);
|
||||||
}
|
}
|
||||||
|
@ -56,13 +58,12 @@ impl VFolder {
|
||||||
pub fn add_file(&mut self, path: &str, file: VFile) {
|
pub fn add_file(&mut self, path: &str, file: VFile) {
|
||||||
let (head, tail) = path
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
if let Some(subfolder) = self.get_folder_mut(head) {
|
if let Some(subfolder) = self.get_folder_mut(head) {
|
||||||
subfolder.add_file(tail, file);
|
subfolder.add_file(tail, file);
|
||||||
} else {
|
} else {
|
||||||
let mut new_folder = VFolder::new();
|
let mut new_folder = Self::new();
|
||||||
new_folder.add_file(tail, file);
|
new_folder.add_file(tail, file);
|
||||||
self.add_existing_folder(head, new_folder);
|
self.add_existing_folder(head, new_folder);
|
||||||
}
|
}
|
||||||
|
@ -72,11 +73,11 @@ impl VFolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively get a subfolder by path.
|
/// 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
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
self.folders.get(head)?.get_folder(tail)
|
self.folders.get(head)?.get_folder(tail)
|
||||||
} else {
|
} else {
|
||||||
|
@ -84,11 +85,10 @@ impl VFolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Recursively get a mutable subfolder by path.
|
/// 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
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
self.folders.get_mut(head)?.get_folder_mut(tail)
|
self.folders.get_mut(head)?.get_folder_mut(tail)
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,11 +96,11 @@ impl VFolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Recursively get a file by path.
|
/// Recursively get a file by path.
|
||||||
|
#[must_use]
|
||||||
pub fn get_file(&self, path: &str) -> Option<&VFile> {
|
pub fn get_file(&self, path: &str) -> Option<&VFile> {
|
||||||
let (head, tail) = path
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
self.folders.get(head)?.get_file(tail)
|
self.folders.get(head)?.get_file(tail)
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,8 +111,7 @@ impl VFolder {
|
||||||
pub fn get_file_mut(&mut self, path: &str) -> Option<&mut VFile> {
|
pub fn get_file_mut(&mut self, path: &str) -> Option<&mut VFile> {
|
||||||
let (head, tail) = path
|
let (head, tail) = path
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.map(|(h, t)| (h, (!t.is_empty()).then_some(t)))
|
.map_or((path, None), |(h, t)| (h, (!t.is_empty()).then_some(t)));
|
||||||
.unwrap_or((path, None));
|
|
||||||
if let Some(tail) = tail {
|
if let Some(tail) = tail {
|
||||||
self.folders.get_mut(head)?.get_file_mut(tail)
|
self.folders.get_mut(head)?.get_file_mut(tail)
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,6 +120,9 @@ impl VFolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Place the folder and its contents on the file system.
|
/// 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<()> {
|
pub fn place(&self, path: &Path) -> io::Result<()> {
|
||||||
fs::create_dir_all(path)?;
|
fs::create_dir_all(path)?;
|
||||||
for (name, folder) in &self.folders {
|
for (name, folder) in &self.folders {
|
||||||
|
@ -141,6 +143,9 @@ impl VFolder {
|
||||||
|
|
||||||
#[cfg(feature = "zip")]
|
#[cfg(feature = "zip")]
|
||||||
/// Zip the folder and its contents into a zip archive.
|
/// 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<()> {
|
pub fn zip(&self, path: &Path) -> io::Result<()> {
|
||||||
use io::Write;
|
use io::Write;
|
||||||
|
|
||||||
|
@ -149,7 +154,7 @@ impl VFolder {
|
||||||
let virtual_files = self.flatten();
|
let virtual_files = self.flatten();
|
||||||
|
|
||||||
for (path, file) in virtual_files {
|
for (path, file) in virtual_files {
|
||||||
writer.start_file(path, Default::default())?;
|
writer.start_file(path, zip::write::SimpleFileOptions::default())?;
|
||||||
match file {
|
match file {
|
||||||
VFile::Text(text) => {
|
VFile::Text(text) => {
|
||||||
writer.write_all(text.as_bytes())?;
|
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.
|
/// Flatten the folder and its contents into a list of files with full paths.
|
||||||
|
#[must_use]
|
||||||
pub fn flatten(&self) -> Vec<(String, &VFile)> {
|
pub fn flatten(&self) -> Vec<(String, &VFile)> {
|
||||||
let mut files = self
|
let mut files = self
|
||||||
.files
|
.files
|
||||||
|
@ -177,7 +183,7 @@ impl VFolder {
|
||||||
let sub_files = folder
|
let sub_files = folder
|
||||||
.flatten()
|
.flatten()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(path, file)| (format!("{}/{}", name, path), file))
|
.map(|(path, file)| (format!("{name}/{path}"), file))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
files.extend(sub_files);
|
files.extend(sub_files);
|
||||||
}
|
}
|
||||||
|
@ -204,19 +210,15 @@ impl TryFrom<&Path> for VFolder {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn try_from(value: &Path) -> Result<Self, Self::Error> {
|
fn try_from(value: &Path) -> Result<Self, Self::Error> {
|
||||||
let mut root_vfolder = VFolder::new();
|
let mut root_vfolder = Self::new();
|
||||||
let root_folder = fs::read_dir(value)?;
|
let fs_root_folder = fs::read_dir(value)?;
|
||||||
for dir_entry in root_folder {
|
for dir_entry in fs_root_folder {
|
||||||
let dir_entry = dir_entry?;
|
let dir_entry = dir_entry?;
|
||||||
let path = dir_entry.path();
|
let path = dir_entry.path();
|
||||||
let name = dir_entry
|
let name = dir_entry.file_name().into_string().ok();
|
||||||
.file_name()
|
|
||||||
.into_string()
|
|
||||||
.map(Some)
|
|
||||||
.unwrap_or_default();
|
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
if path.is_dir() {
|
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() {
|
} else if path.is_file() {
|
||||||
let data = fs::read(path)?;
|
let data = fs::read(path)?;
|
||||||
root_vfolder.add_file(&name, VFile::Binary(data));
|
root_vfolder.add_file(&name, VFile::Binary(data));
|
||||||
|
@ -236,7 +238,8 @@ impl TryFrom<&Path> for VFolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// File representation in virtual file system
|
/// 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 {
|
pub enum VFile {
|
||||||
/// Text file
|
/// Text file
|
||||||
Text(String),
|
Text(String),
|
||||||
|
@ -246,17 +249,17 @@ pub enum VFile {
|
||||||
|
|
||||||
impl From<String> for VFile {
|
impl From<String> for VFile {
|
||||||
fn from(value: String) -> Self {
|
fn from(value: String) -> Self {
|
||||||
VFile::Text(value)
|
Self::Text(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<&str> for VFile {
|
impl From<&str> for VFile {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
VFile::Text(value.to_string())
|
Self::Text(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Default for VFile {
|
impl Default for VFile {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
VFile::Text(String::new())
|
Self::Text(String::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue