From 892d82588fbddfe3b81a1f0272b9ef173a9b9c8c Mon Sep 17 00:00:00 2001 From: Logan Wemyss <10540653-VixieTSQ@users.noreply.gitlab.com> Date: Thu, 13 Oct 2022 11:58:41 -0600 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Partially=20implement=20info=20subc?= =?UTF-8?q?ommand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rustfmt.toml | 72 ++++++++++++ src/blocks/intermediary/collisions.rs | 60 +++++----- src/blocks/intermediary/data.rs | 60 +++++----- src/blocks/intermediary/metadata.rs | 30 +---- src/blocks/intermediary/mod.rs | 1 - src/blocks/intermediary/rules.rs | 11 +- src/blocks/raw/de.rs | 156 ++++++++++++-------------- src/blocks/raw/mod.rs | 11 +- src/blocks/raw/property.rs | 25 +---- src/cmd/info.rs | 48 ++++++++ src/cmd/intermediary.rs | 23 ++-- src/cmd/mod.rs | 4 +- src/main.rs | 8 +- src/util/file/input.rs | 19 +--- src/util/file/mod.rs | 2 +- src/util/file/output.rs | 2 +- src/util/identifier.rs | 48 +++----- src/util/mod.rs | 2 +- 18 files changed, 314 insertions(+), 268 deletions(-) create mode 100644 rustfmt.toml create mode 100644 src/cmd/info.rs diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..a471c17 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,72 @@ +max_width = 160 +hard_tabs = false +tab_spaces = 4 +newline_style = "Unix" +indent_style = "Block" +use_small_heuristics = "Off" +chain_width = 85 +wrap_comments = true +format_code_in_doc_comments = false +comment_width = 80 +normalize_comments = true +normalize_doc_attributes = true +format_strings = true +format_macro_matchers = true +format_macro_bodies = true +hex_literal_case = "Preserve" +empty_item_single_line = true +struct_lit_single_line = true +struct_lit_width = 18 +fn_single_line = true +where_single_line = false +imports_indent = "Block" +imports_layout = "Mixed" +imports_granularity = "Module" +group_imports = "StdExternalCrate" +reorder_imports = true +reorder_modules = true +reorder_impl_items = true +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +short_array_element_width_threshold = 16 +overflow_delimited_expr = true +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = true +match_arm_leading_pipes = "Never" +force_multiline_blocks = false +fn_args_layout = "Tall" +brace_style = "SameLineWhere" +control_brace_style = "AlwaysSameLine" +trailing_semicolon = true +trailing_comma = "Vertical" +match_block_trailing_comma = true +blank_lines_upper_bound = 1 +blank_lines_lower_bound = 0 +edition = "2021" +version = "One" +inline_attribute_width = 0 +format_generated_files = false +merge_derives = true +use_try_shorthand = true +use_field_init_shorthand = true +force_explicit_abi = true +condense_wildcard_suffixes = false +color = "Auto" +required_version = "1.5.1" +unstable_features = false +disable_all_formatting = false +skip_children = false +hide_parse_errors = false +error_on_line_overflow = false +error_on_unformatted = false +ignore = [ + "crates/block_parser" +] +emit_mode = "Files" +make_backup = false diff --git a/src/blocks/intermediary/collisions.rs b/src/blocks/intermediary/collisions.rs index 107ad8e..a5c5f28 100644 --- a/src/blocks/intermediary/collisions.rs +++ b/src/blocks/intermediary/collisions.rs @@ -1,10 +1,9 @@ use ahash::{AHashMap, AHashSet}; +use serde::de::{DeserializeSeed, IgnoredAny, Visitor}; use serde::Deserialize; -use serde::de::{Visitor, IgnoredAny, DeserializeSeed}; - -use crate::blocks::raw::property::{EnumProperty, PropertyKind}; use super::rules::ModernPropertyRules; +use crate::blocks::raw::property::{EnumProperty, PropertyKind}; /// A collection of possible property collisions in raw data. /// @@ -27,9 +26,7 @@ pub struct CollisionList<'raw> { } impl<'raw> CollisionList<'raw> { - pub fn should_exit(&self) -> bool { - !self.by_name.is_empty() - } + pub fn should_exit(&self) -> bool { !self.by_name.is_empty() } /// Displays a summary of the different collisions found in the raw data. pub fn display(&self) { @@ -62,41 +59,42 @@ pub struct CollisionRuleProvider<'a, 'raw>(Option<&'a ModernPropertyRules<'raw>> impl<'a, 'raw> CollisionRuleProvider<'a, 'raw> { /// Constructs a new `CollisionRuleProvider` given a set of rules - pub fn new(rules: Option<&'a ModernPropertyRules<'raw>>) -> Self { - Self(rules) - } + pub fn new(rules: Option<&'a ModernPropertyRules<'raw>>) -> Self { Self(rules) } /// This transformation does two checks: - /// - First it makes sure the property name is not `"type"`, this will get transformed into `"kind"` - /// - Secondly it uses the rules, if present, to replace the property name if there's a match based on the property values + /// - First it makes sure the property name is not `"type"`, this will get + /// transformed into `"kind"` + /// - Secondly it uses the rules, if present, to replace the property name + /// if there's a match based on the property values pub fn transform<'b, I>(&'b self, properties: I) -> impl Iterator)> + 'b where I: IntoIterator)> + 'b, { - properties.into_iter() - .map(|(name, property)| { - let name = if name == "type" { "kind" } else { name }; - if let Some(rules) = self.0 { - rules.transform(name, property) - } else { - (name, property) - } - }) + properties.into_iter().map(|(name, property)| { + let name = if name == "type" { + "kind" + } else { + name + }; + if let Some(rules) = self.0 { + rules.transform(name, property) + } else { + (name, property) + } + }) } } impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CollisionRuleProvider<'a, 'raw> { type Value = CollisionList<'raw>; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a 1.13+ minecraft-generated block list") - } + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a 1.13+ minecraft-generated block list") } /// Simply collect all the properties and keep the ones /// that share either name or values fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, + where + A: serde::de::MapAccess<'de>, { let mut by_name = AHashMap::<&'raw str, AHashSet>::new(); let mut by_values = AHashMap::, AHashSet<&'raw str>>::new(); @@ -115,8 +113,8 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CollisionRuleProvider<'a, 'raw> { } else { by_name.insert(name, AHashSet::from([property])); } - } - _ => {} + }, + _ => {}, } } } @@ -124,10 +122,7 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CollisionRuleProvider<'a, 'raw> { by_name.retain(|_, set| set.len() > 1); by_values.retain(|_, set| set.len() > 1); - Ok(CollisionList { - by_name, - by_values, - }) + Ok(CollisionList { by_name, by_values }) } } @@ -136,7 +131,7 @@ impl<'a, 'raw, 'de: 'raw> DeserializeSeed<'de> for CollisionRuleProvider<'a, 'ra fn deserialize(self, deserializer: D) -> Result where - D: serde::Deserializer<'de> + D: serde::Deserializer<'de>, { deserializer.deserialize_map(self) } @@ -149,4 +144,3 @@ struct RawBlockData<'raw> { #[serde(rename = "states")] _states: IgnoredAny, } - diff --git a/src/blocks/intermediary/data.rs b/src/blocks/intermediary/data.rs index 22262d3..736817c 100644 --- a/src/blocks/intermediary/data.rs +++ b/src/blocks/intermediary/data.rs @@ -1,6 +1,8 @@ use ahash::RandomState; use hashlink::LinkedHashMap; use serde::{Deserialize, Serialize}; + +use super::MetaData; use crate::blocks::raw::property::EnumProperty; use crate::util::identifier::Identifier; @@ -14,23 +16,27 @@ pub type BlockList<'raw> = LinkedHashMap, ModernBlockData<'raw> /// The compact blockstates format. /// /// In this format there are two lists: -/// - The first list is a list of all possible properties. -/// i.e. a property name mapped to more than one property value. -/// - The second list is a list of all the blocks. -/// i.e. a collection of blockstates, if the block has one or more properties -/// it will have these listed referring to the first list when it's an enum property. -/// If the block has more than one blockstate, there will also be a `default_id` field. +/// - The first list is a list of all possible properties. i.e. a property name +/// mapped to more than one property value. +/// - The second list is a list of all the blocks. i.e. a collection of +/// blockstates, if the block has one or more properties it will have these +/// listed referring to the first list when it's an enum property. If the +/// block has more than one blockstate, there will also be a `default_id` +/// field. #[derive(Debug, Serialize, Deserialize)] pub struct ModernBlockList<'raw> { #[serde(borrow)] - properties: PropertyList<'raw>, + pub metadata: Option>, + #[serde(borrow)] + pub properties: PropertyList<'raw>, #[serde(borrow)] - blocks: BlockList<'raw>, + pub blocks: BlockList<'raw>, } impl<'raw> ModernBlockList<'raw> { - pub(crate) fn new(properties: PropertyList<'raw>, blocks: BlockList<'raw>) -> Self { + pub(crate) fn new(metadata: Option>, properties: PropertyList<'raw>, blocks: BlockList<'raw>) -> Self { ModernBlockList { + metadata, properties, blocks, } @@ -39,25 +45,29 @@ impl<'raw> ModernBlockList<'raw> { /// Compact way of identifying block data. /// -/// Only if the block has one ore more properties, the [`ModernBlockData::kinds`] -/// will be serialized. If the block has more than one blockstate, -/// a default_id field will be serialized as well. +/// Only if the block has one ore more properties, the +/// [`ModernBlockData::kinds`] will be serialized. If the block has more than +/// one blockstate, a default_id field will be serialized as well. #[derive(Debug, Serialize, Deserialize)] pub struct ModernBlockData<'raw> { - #[serde(borrow, skip_serializing_if = "LinkedHashMap::is_empty", rename = "properties")] - kinds: LinkedHashMap<&'raw str, PropertyValue<'raw>, RandomState>, + #[serde(borrow, skip_serializing_if = "Option::is_none", rename = "properties")] + kinds: Option, RandomState>>, #[serde(rename = "base")] - base_id: i32, + pub base_id: i32, #[serde(skip_serializing_if = "Option::is_none", rename = "default")] - default_id: Option, + pub default_id: Option, } impl<'raw> ModernBlockData<'raw> { pub fn new(kinds: LinkedHashMap<&'raw str, PropertyValue<'raw>, RandomState>, base_id: i32, default_id: Option) -> Self { ModernBlockData { - kinds, + kinds: if kinds.is_empty() { + None + } else { + Some(kinds) + }, base_id, - default_id + default_id, } } } @@ -72,15 +82,9 @@ pub enum PropertyValue<'raw> { } impl<'raw> PropertyValue<'raw> { - pub fn bool() -> Self { - Self::Bool("bool") - } + pub fn bool() -> Self { Self::Bool("bool") } - pub fn enum_name(value: &'raw str) -> Self { - Self::Enum(value) - } - - pub fn range(start: u8, end: u8) -> Self { - Self::Range([start, end]) - } + pub fn enum_name(value: &'raw str) -> Self { Self::Enum(value) } + + pub fn range(start: u8, end: u8) -> Self { Self::Range([start, end]) } } diff --git a/src/blocks/intermediary/metadata.rs b/src/blocks/intermediary/metadata.rs index 787fcf9..44ca444 100644 --- a/src/blocks/intermediary/metadata.rs +++ b/src/blocks/intermediary/metadata.rs @@ -1,36 +1,14 @@ -use std::borrow::Cow; - use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize)] pub struct MetaData<'raw> { - id: i32, + pub id: i32, #[serde(skip_serializing_if = "Option::is_none")] - name: Option<&'raw str>, + pub name: Option<&'raw str>, #[serde(skip_serializing_if = "Option::is_none")] - note: Option<&'raw str>, + pub note: Option<&'raw str>, } impl<'raw> MetaData<'raw> { - pub fn new(id: i32, name: Option<&'raw str>, note: Option<&'raw str>) -> Self { - Self { - id, - name, - note, - } - } - - pub fn id(&self) -> i32 { - self.id - } - - pub fn name(&self) -> Cow<'raw, str> { - self.name - .map(|name| name.into()) - .unwrap_or(Cow::Owned(self.id.to_string())) - } - - pub fn note(&self) -> Option<&'raw str> { - self.note - } + pub fn new(id: i32, name: Option<&'raw str>, note: Option<&'raw str>) -> Self { Self { id, name, note } } } diff --git a/src/blocks/intermediary/mod.rs b/src/blocks/intermediary/mod.rs index 95114b5..8b7b605 100644 --- a/src/blocks/intermediary/mod.rs +++ b/src/blocks/intermediary/mod.rs @@ -4,4 +4,3 @@ mod metadata; pub mod rules; pub use metadata::MetaData; - diff --git a/src/blocks/intermediary/rules.rs b/src/blocks/intermediary/rules.rs index 4e52853..8262d18 100644 --- a/src/blocks/intermediary/rules.rs +++ b/src/blocks/intermediary/rules.rs @@ -1,10 +1,10 @@ use ahash::RandomState; use hashlink::LinkedHashMap; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::blocks::raw::property::{EnumProperty, PropertyKind}; -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] #[serde(from = "LinkedHashMap<&'raw str, EnumProperty<'raw>, RandomState>")] pub struct ModernPropertyRules<'raw> { #[serde(borrow, flatten)] @@ -15,7 +15,7 @@ impl<'raw> ModernPropertyRules<'raw> { pub fn transform(&self, name: &'raw str, property: PropertyKind<'raw>) -> (&'raw str, PropertyKind<'raw>) { match &property { PropertyKind::Enum(enum_property) => (self.rule_data.get(&enum_property).cloned().unwrap_or(name), property), - _ => (name, property) + _ => (name, property), } } } @@ -23,10 +23,7 @@ impl<'raw> ModernPropertyRules<'raw> { impl<'raw> From, RandomState>> for ModernPropertyRules<'raw> { fn from(other: LinkedHashMap<&'raw str, EnumProperty<'raw>, RandomState>) -> Self { Self { - rule_data: other.into_iter() - .map(|(name, values)| (values, name)) - .collect(), + rule_data: other.into_iter().map(|(name, values)| (values, name)).collect(), } } } - diff --git a/src/blocks/raw/de.rs b/src/blocks/raw/de.rs index 0cb2405..d156809 100644 --- a/src/blocks/raw/de.rs +++ b/src/blocks/raw/de.rs @@ -1,54 +1,52 @@ use ahash::RandomState; use hashlink::LinkedHashMap; -use serde::de::{Visitor, DeserializeSeed}; +use serde::de::{DeserializeSeed, Visitor}; -use crate::blocks::intermediary::data::{ModernBlockList, PropertyValue, ModernBlockData}; +use super::property::PropertyKind; +use super::RawBlockData; +use crate::blocks::intermediary::data::{ModernBlockData, ModernBlockList, PropertyValue}; use crate::blocks::intermediary::rules::ModernPropertyRules; use crate::util::identifier::Identifier; -use super::RawBlockData; -use super::property::PropertyKind; - pub struct CompactRuleProvider<'a, 'raw>(Option<&'a ModernPropertyRules<'raw>>); impl<'a, 'raw> CompactRuleProvider<'a, 'raw> { - pub fn new(rules: Option<&'a ModernPropertyRules<'raw>>) -> Self { - Self(rules) - } + pub fn new(rules: Option<&'a ModernPropertyRules<'raw>>) -> Self { Self(rules) } /// This transformation does two checks: /// - First it makes sure the property name is not `"type"`, this will get - /// transformed into `"kind"` + /// transformed into `"kind"` /// - Secondly it uses the rules, if present, to replace the property name - /// if there's a match based on the property values + /// if there's a match based on the property values pub fn transform<'b, I>(&'b self, properties: I) -> impl Iterator)> + 'b where I: IntoIterator)> + 'b, { - properties.into_iter() - .map(|(name, property)| { - let name = if name == "type" { "kind" } else { name }; - if let Some(rules) = self.0 { - rules.transform(name, property) - } else { - (name, property) - } - }) + properties.into_iter().map(|(name, property)| { + let name = if name == "type" { + "kind" + } else { + name + }; + if let Some(rules) = self.0 { + rules.transform(name, property) + } else { + (name, property) + } + }) } } impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { type Value = ModernBlockList<'raw>; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a 1.13+ minecraft-generated block list") - } + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("a 1.13+ minecraft-generated block list") } /// This implementation verifies the data /// and makes sure it follows the expected pattern. fn visit_map(self, mut map: A) -> Result - where - A: serde::de::MapAccess<'de>, + where + A: serde::de::MapAccess<'de>, { // Overall lists that will be passed to ModernBlockList let mut properties = LinkedHashMap::with_hasher(RandomState::default()); @@ -57,10 +55,10 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { while let Some((identifier, block)) = map.next_entry::, RawBlockData<'raw>>()? { let property_count = block.property_count(); let state_count = block.state_count(); - - // make sure there is the correct amound of blockstates + + // make sure there is the correct amount of blockstates if block.states.len() != state_count { - return Err(serde::de::Error::invalid_length(block.states.len(), &format!("{} entries", state_count).as_str())) + return Err(serde::de::Error::invalid_length(block.states.len(), &format!("{} entries", state_count).as_str())); } let base_id = block.states[0].id; @@ -68,9 +66,7 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { for state in &block.states { // Make sure the blockstate has the correct amount of property values if state.properties.len() != property_count { - return Err(serde::de::Error::invalid_length( - state.properties.len(), &format!("{} entries", property_count).as_str(), - )); + return Err(serde::de::Error::invalid_length(state.properties.len(), &format!("{} entries", property_count).as_str())); } // Check the network values for consistency, @@ -81,38 +77,33 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { let mut prev_factor = 1; let mut offset = 0; for (&name, &value) in state.properties.iter().rev() { - let values = block.properties.iter().find_map(|(&a, b)| if a == name { Some(b) } else { None }) - .ok_or(serde::de::Error::custom( - format!("found a non-matching a property \"{}\" for \"{}\"", name, identifier) - ))?; + let values = block + .properties + .iter() + .find_map(|(&a, b)| { + if a == name { + Some(b) + } else { + None + } + }) + .ok_or(serde::de::Error::custom(format!("found a non-matching a property \"{}\" for \"{}\"", name, identifier)))?; match values.iter().position(|&x| x == value) { Some(index) => { factor *= prev_factor; prev_factor = values.len(); offset += factor * index; - } + }, None => { - return Err(serde::de::Error::custom( - format!( - "invalid property value \"{}\" found while deserializing \"{}\"", - value, - identifier - ), - )); - } + return Err(serde::de::Error::custom(format!("invalid property value \"{}\" found while deserializing \"{}\"", value, identifier))); + }, } } // Step 2: make sure that the base id plus offset equals the given blockstate id let id = base_id + offset as i32; if id != state.id { - return Err(serde::de::Error::custom( - format!("incorrect id match for \"{}\", found {} while expecting {}", - identifier, - state.id, - id - ), - )); + return Err(serde::de::Error::custom(format!("incorrect id match for \"{}\", found {} while expecting {}", identifier, state.id, id))); } // try to find a default blockstate other than base id if state.default { @@ -121,45 +112,43 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { } // only if base id is different from default_id should default_id be remembered // (see below when adding new block) - let default_id = default_id.and_then(|id| if id == base_id { - None - } else { - Some(id) + let default_id = default_id.and_then(|id| { + if id == base_id { + None + } else { + Some(id) + } }); // Extend the list of properties with the properties of this block - properties.extend( - self.transform(block.properties()) - .filter_map(|(name, property)| { - match property { - PropertyKind::Enum(property) => Some((name, property)), - _ => None, + properties.extend(self.transform(block.properties()).filter_map(|(name, property)| match property { + PropertyKind::Enum(property) => Some((name, property)), + _ => None, + })); + + // Collect the property types to add to the compacted form of this block (see + // below) + let properties = block + .properties() + .map(|(name, kind)| { + if name == "type" { + ("kind", kind) + } else { + (name, kind) } }) - ); - - // Collect the property types to add to the compacted form of this block (see below) - let properties = block.properties() - .map(|(name, kind)| if name == "type" { - ("kind", kind) - } else { - (name, kind) - }) .map(|(name, kind)| { - ( - name, - match kind { - PropertyKind::Bool => PropertyValue::bool(), - PropertyKind::Int([start, end]) => PropertyValue::range(start, end), - PropertyKind::Enum(_) => { - if let Some(rules) = self.0 { - PropertyValue::enum_name(rules.transform(name, kind).0) - } else { - PropertyValue::enum_name(name) - } + (name, match kind { + PropertyKind::Bool => PropertyValue::bool(), + PropertyKind::Int([start, end]) => PropertyValue::range(start, end), + PropertyKind::Enum(_) => { + if let Some(rules) = self.0 { + PropertyValue::enum_name(rules.transform(name, kind).0) + } else { + PropertyValue::enum_name(name) } }, - ) + }) }) .collect(); @@ -167,7 +156,7 @@ impl<'a, 'raw, 'de: 'raw> Visitor<'de> for CompactRuleProvider<'a, 'raw> { blocks.insert(identifier, ModernBlockData::new(properties, base_id, default_id)); } - Ok(ModernBlockList::new(properties, blocks)) + Ok(ModernBlockList::new(todo!(), properties, blocks)) } } @@ -176,9 +165,8 @@ impl<'a, 'raw, 'de: 'raw> DeserializeSeed<'de> for CompactRuleProvider<'a, 'raw> fn deserialize(self, deserializer: D) -> Result where - D: serde::Deserializer<'de> + D: serde::Deserializer<'de>, { deserializer.deserialize_map(self) } } - diff --git a/src/blocks/raw/mod.rs b/src/blocks/raw/mod.rs index c054e01..e159473 100644 --- a/src/blocks/raw/mod.rs +++ b/src/blocks/raw/mod.rs @@ -17,9 +17,7 @@ pub struct RawBlockData<'raw> { } impl<'raw> RawBlockData<'raw> { - pub fn property_count(&self) -> usize { - self.properties.len() - } + pub fn property_count(&self) -> usize { self.properties.len() } pub fn state_count(&self) -> usize { let mut number = 1; @@ -29,12 +27,10 @@ impl<'raw> RawBlockData<'raw> { number } - pub fn properties<'b>(&'b self) -> impl Iterator)> + 'b { + pub fn properties<'b>(&'b self) -> impl Iterator)> + 'b { self.properties .iter() - .filter_map(|(name, values)| { - PropertyKind::try_from(values.as_slice()).ok().map(|property| (*name, property)) - }) + .filter_map(|(name, values)| PropertyKind::try_from(values.as_slice()).ok().map(|property| (*name, property))) } } @@ -46,4 +42,3 @@ pub struct RawBlockState<'raw> { #[serde(default)] default: bool, } - diff --git a/src/blocks/raw/property.rs b/src/blocks/raw/property.rs index 4a2bb1b..a4dd18b 100644 --- a/src/blocks/raw/property.rs +++ b/src/blocks/raw/property.rs @@ -18,7 +18,7 @@ pub enum PropertyKindParseError { #[error("First value was a boolean but second value was not")] BooleanInvalidType, #[error("Invalid integer value")] - IntError(#[from] ParseIntError) + IntError(#[from] ParseIntError), } impl<'b, 'raw: 'b> TryFrom<&'b [&'raw str]> for PropertyKind<'raw> { @@ -71,7 +71,7 @@ impl<'raw> PropertyKind<'raw> { match self { PropertyKind::Bool => 2, PropertyKind::Int(range) => (range[1] - range[0] + 1) as usize, - PropertyKind::Enum(values) => values.fields().len() + PropertyKind::Enum(values) => values.fields().len(), } } } @@ -91,23 +91,15 @@ impl<'raw> EnumProperty<'raw> { } } - pub fn fields<'b>(&'b self) -> &'b [&'raw str] { - &self.values - } + pub fn fields<'b>(&'b self) -> &'b [&'raw str] { &self.values } } impl<'raw> From> for EnumProperty<'raw> { - fn from(values: Vec<&'raw str>) -> Self { - Self { - values, - } - } + fn from(values: Vec<&'raw str>) -> Self { Self { values } } } impl<'raw> Into> for EnumProperty<'raw> { - fn into(self) -> Vec<&'raw str> { - self.values - } + fn into(self) -> Vec<&'raw str> { self.values } } #[cfg(test)] @@ -121,11 +113,6 @@ mod tests { let values = vec!["value1", "value2"]; let enum_property = EnumProperty::new(&values); - assert_de_tokens(&enum_property, &[ - Token::Seq { len: Some(2) }, - Token::BorrowedStr("value1"), - Token::BorrowedStr("value2"), - Token::SeqEnd, - ]); + assert_de_tokens(&enum_property, &[Token::Seq { len: Some(2) }, Token::BorrowedStr("value1"), Token::BorrowedStr("value2"), Token::SeqEnd]); } } diff --git a/src/cmd/info.rs b/src/cmd/info.rs new file mode 100644 index 0000000..d997086 --- /dev/null +++ b/src/cmd/info.rs @@ -0,0 +1,48 @@ +use anyhow::Result; +use clap::Args; + +use crate::blocks::intermediary::data::ModernBlockList; +use crate::util::file::InputFile; + +#[derive(Args, Debug)] +pub struct InfoCommand { + /// File containing intermediary data from mc-data + input: InputFile, +} + +impl InfoCommand { + pub fn display_info(&self) -> Result<()> { + let data: ModernBlockList = self.input.deserialized()?; + + let version; + let note; + if let Some(meta) = data.metadata { + let id = meta.id; + version = if let Some(name) = meta.name { + format!("Minecraft blockdata version {id} ({name})\n") + } else { + format!("Minecraft blockdata version {id}\n") + }; + + note = if let Some(x) = meta.note { + format!("Note: {x}\n") + } else { + String::from("") + }; + } else { + version = String::from(""); + note = String::from(""); + }; + + let num_of_blocks = data.blocks.len(); + let num_of_enum_props = data.properties.len(); + + println!( + "{version}{note} +Loaded {num_of_blocks} blocks successfully +There are {num_of_enum_props} enum properties present" + ); + + Ok(()) + } +} diff --git a/src/cmd/intermediary.rs b/src/cmd/intermediary.rs index 7da79fb..8856106 100644 --- a/src/cmd/intermediary.rs +++ b/src/cmd/intermediary.rs @@ -1,9 +1,9 @@ -use clap::Args; use anyhow::Result; +use clap::Args; use serde::de::DeserializeSeed; use serde_json::Deserializer; -use crate::blocks::intermediary::collisions::{CollisionRuleProvider, CollisionList}; +use crate::blocks::intermediary::collisions::{CollisionList, CollisionRuleProvider}; use crate::blocks::intermediary::data::ModernBlockList; use crate::blocks::intermediary::rules::ModernPropertyRules; use crate::blocks::raw::de::CompactRuleProvider; @@ -24,7 +24,11 @@ pub struct IntermediaryCommand { rules: Option, #[clap(short, long)] output: Option, - #[clap(long = "no-pretty")] + #[clap(long)] + version_id: Option, + #[clap(long)] + version_name: Option, + #[clap(long)] /// Does not pretty-print the resulting json data no_pretty: bool, } @@ -35,19 +39,17 @@ impl IntermediaryCommand { let data = self.input.data(); // Load rules - let rules: Option = self.rules - .as_ref() - .map(|rules| rules.deserialized()).transpose()?; + let rules: Option = self.rules.as_ref().map(|rules| rules.deserialized()).transpose()?; // Property collisions eprintln!("Checking for property collisions..."); let collisions = CollisionRuleProvider::new(rules.as_ref()); - let collisions: CollisionList = collisions.deserialize(&mut Deserializer::from_str(data))?; + let collisions: CollisionList = collisions.deserialize(&mut Deserializer::from_str(data))?; collisions.display(); if collisions.should_exit() { eprintln!("Could not continue due to one or more collisions in block properties.\nPlease specify a rules file to resolve these"); - return Ok(()) + return Ok(()); } eprintln!("No serious collisions found, slight inefficiencies will have been signaled by now. \u{2705}"); @@ -67,7 +69,7 @@ impl IntermediaryCommand { } else { eprintln!("Aborted"); } - } + }, None => { let result = if self.no_pretty { serde_json::to_string(&modern_data)? @@ -76,10 +78,9 @@ impl IntermediaryCommand { }; println!("{}", result); eprintln!("========\nSuccessfully compacted data \u{2705}"); - } + }, } Ok(()) } } - diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index ff4737c..35d4067 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -1,3 +1,5 @@ -pub mod intermediary; +mod info; +mod intermediary; +pub use info::InfoCommand; pub use intermediary::IntermediaryCommand; diff --git a/src/main.rs b/src/main.rs index 291ebac..fe3ce4b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use anyhow::Context; use clap::{Parser, Subcommand}; -use cmd::IntermediaryCommand; +use cmd::{InfoCommand, IntermediaryCommand}; pub mod blocks; pub mod cmd; @@ -16,14 +16,14 @@ pub struct Cli { #[derive(Subcommand, Debug)] pub enum SubCommands { Intermediary(IntermediaryCommand), + Info(InfoCommand), } fn main() -> anyhow::Result<()> { let cli = Cli::parse(); match cli.command { - SubCommands::Intermediary(cmd) => { - cmd.generate_intermediate().with_context(|| "Error while generating data") - } + SubCommands::Intermediary(cmd) => cmd.generate_intermediate().context("Error while generating data"), + SubCommands::Info(cmd) => cmd.display_info().context("Error while displaying info"), } } diff --git a/src/util/file/input.rs b/src/util/file/input.rs index 9ac94a4..b966f3e 100644 --- a/src/util/file/input.rs +++ b/src/util/file/input.rs @@ -1,13 +1,13 @@ use std::io; use std::path::PathBuf; use std::str::FromStr; -use anyhow::Context; +use anyhow::Context; use serde::Deserialize; /// This is the representation of an /// input file to be parsed by clap. Upon -/// parsing, this will open and read the specified file if posssible. +/// parsing, this will open and read the specified file if possible. #[derive(Debug)] pub struct InputFile { name: PathBuf, @@ -16,20 +16,16 @@ pub struct InputFile { impl InputFile { /// Returns the name of the file - pub fn name(&self) -> &PathBuf { - &self.name - } + pub fn name(&self) -> &PathBuf { &self.name } /// Convenience function to automatically deserialize pub fn deserialized<'raw, T: Deserialize<'raw>>(&'raw self) -> anyhow::Result { - let result = serde_json::from_str::(&self.contents).with_context(|| "Could not deserialize to the requested format")?; + let result = serde_json::from_str::(&self.contents).context("Could not deserialize to the requested format")?; Ok(result) } /// Returns raw content of the file - pub fn data(&self) -> &str { - &self.contents - } + pub fn data(&self) -> &str { &self.contents } } impl FromStr for InputFile { @@ -38,9 +34,6 @@ impl FromStr for InputFile { fn from_str(s: &str) -> Result { let name = PathBuf::from(s); let contents = std::fs::read_to_string(&name)?; - Ok(Self { - name, - contents, - }) + Ok(Self { name, contents }) } } diff --git a/src/util/file/mod.rs b/src/util/file/mod.rs index 7b3a403..94a92d5 100644 --- a/src/util/file/mod.rs +++ b/src/util/file/mod.rs @@ -2,4 +2,4 @@ mod input; mod output; pub use input::InputFile; -pub use output::OutputFile; \ No newline at end of file +pub use output::OutputFile; diff --git a/src/util/file/output.rs b/src/util/file/output.rs index ab0428b..d6e1128 100644 --- a/src/util/file/output.rs +++ b/src/util/file/output.rs @@ -33,4 +33,4 @@ impl FromStr for OutputFile { output: PathBuf::from(s), }) } -} \ No newline at end of file +} diff --git a/src/util/identifier.rs b/src/util/identifier.rs index 4d9f733..f0f885c 100644 --- a/src/util/identifier.rs +++ b/src/util/identifier.rs @@ -1,4 +1,5 @@ use std::fmt::{Display, Formatter}; + use nom::branch::alt; use nom::bytes::complete::take_while; use nom::character::complete::char; @@ -14,9 +15,7 @@ pub struct Identifier<'a> { } impl<'a> Display for Identifier<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}:{}", self.namespace, self.location) - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}:{}", self.namespace, self.location) } } impl<'a> Identifier<'a> { @@ -34,13 +33,9 @@ impl<'a> Identifier<'a> { } } - pub fn namespace(&self) -> &'a str { - self.namespace - } + pub fn namespace(&self) -> &'a str { self.namespace } - pub fn location(&self) -> &'a str { - self.location - } + pub fn location(&self) -> &'a str { self.location } } impl<'a> TryFrom<&'a str> for Identifier<'a> { @@ -50,10 +45,8 @@ impl<'a> TryFrom<&'a str> for Identifier<'a> { let namespace_domain = take_while::<_, _, Error<&'a str>>(|i| "0123456789abcdefghijklmnopqrstuvwxyz-_.".contains(i)); let location_domain = take_while::<_, _, Error<&'a str>>(|i| "0123456789abcdefghijklmnopqrstuvwxyz-_./".contains(i)); let namespace_location = separated_pair(namespace_domain, char(':'), location_domain); - let location_only = map( - take_while::<_, _, Error<&'a str>>(|i| "0123456789abcdefghijklmnopqrstuvwxyz-_./".contains(i)), - |location: &'a str| ("minecraft", location) - ); + let location_only = + map(take_while::<_, _, Error<&'a str>>(|i| "0123456789abcdefghijklmnopqrstuvwxyz-_./".contains(i)), |location: &'a str| ("minecraft", location)); let (input, (namespace, location)) = alt((namespace_location, location_only))(input).unwrap(); if !input.is_empty() { Err(location.len()) @@ -69,16 +62,20 @@ impl<'a> TryFrom<&'a str> for Identifier<'a> { impl<'de: 'a, 'a> Deserialize<'de> for Identifier<'a> { fn deserialize(deserializer: D) -> Result where - D: serde::Deserializer<'de> + D: serde::Deserializer<'de>, { let ident = <&'a str as Deserialize>::deserialize(deserializer)?; - ident.try_into() + ident + .try_into() .map_err(|e| serde::de::Error::custom(format!("invalid character at position {}", e))) } } impl<'a> Serialize for Identifier<'a> { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { let mut result = String::with_capacity(self.namespace.len() + 1 + self.location.len()); result.push_str(self.namespace); result.push(':'); @@ -89,28 +86,19 @@ impl<'a> Serialize for Identifier<'a> { #[cfg(test)] mod tests { - use serde_test::{assert_de_tokens, Token, assert_de_tokens_error}; + use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; use super::*; #[test] fn test_identifier_de() { let identifier = Identifier::from_location("test1"); - assert_de_tokens(&identifier, &[ - Token::BorrowedStr("test1"), - ]); - + assert_de_tokens(&identifier, &[Token::BorrowedStr("test1")]); + let identifier = Identifier::from_full("test_2", "other/value"); - assert_de_tokens(&identifier, &[ - Token::BorrowedStr("test_2:other/value"), - ]); + assert_de_tokens(&identifier, &[Token::BorrowedStr("test_2:other/value")]); } #[test] - fn test_identifier_de_error() { - assert_de_tokens_error::( - &[ - Token::BorrowedStr("test/2:other"), - ], "invalid character at position 6") - } + fn test_identifier_de_error() { assert_de_tokens_error::(&[Token::BorrowedStr("test/2:other")], "invalid character at position 6") } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 604730e..9615704 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,2 +1,2 @@ pub mod file; -pub mod identifier; \ No newline at end of file +pub mod identifier;