diff --git a/src/metadata/file.rs b/src/metadata/file.rs index 406052d4..676b3701 100644 --- a/src/metadata/file.rs +++ b/src/metadata/file.rs @@ -18,9 +18,9 @@ use super::{ #[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct File { name: Filename, - display_name: Option, - detail: Vec, - condition: Option, + display_name: Option>, + detail: Box<[MessageContent]>, + condition: Option>, } impl File { @@ -72,7 +72,7 @@ impl File { /// Set the name to be displayed for the file in messages, formatted using /// CommonMark. pub fn set_display_name(&mut self, display_name: String) -> &mut Self { - self.display_name = Some(display_name); + self.display_name = Some(display_name.into_boxed_str()); self } @@ -93,7 +93,7 @@ impl File { detail: Vec, ) -> Result<&mut Self, MultilingualMessageContentsError> { validate_message_contents(&detail)?; - self.detail = detail; + self.detail = detail.into_boxed_slice(); Ok(self) } @@ -104,20 +104,20 @@ impl File { /// Set the condition string. pub fn set_condition(&mut self, condition: String) -> &mut Self { - self.condition = Some(condition); + self.condition = Some(condition.into_boxed_str()); self } } /// Represents a case-insensitive filename. #[derive(Clone, Debug, Default)] -pub struct Filename(String); +pub struct Filename(Box); impl Filename { /// Construct a Filename using the given string. #[must_use] pub fn new(s: String) -> Self { - Filename(s) + Filename(s.into()) } /// Get this Filename as a string. @@ -170,7 +170,7 @@ impl TryFromYaml for File { YamlData::String(s) => Ok(File { name: Filename::new(s.clone()), display_name: None, - detail: Vec::new(), + detail: Box::default(), condition: None, }), YamlData::Hash(h) => { @@ -185,14 +185,14 @@ impl TryFromYaml for File { "detail", YamlObjectType::PluginCleaningData, )?, - None => Vec::new(), + None => Box::default(), }; let condition = parse_condition(h, YamlObjectType::File)?; Ok(File { name: Filename::new(name.to_string()), - display_name: display_name.map(|(_, s)| s.to_string()), + display_name: display_name.map(|(_, s)| s.into()), detail, condition, }) diff --git a/src/metadata/group.rs b/src/metadata/group.rs index 00c20a0c..cbbb235c 100644 --- a/src/metadata/group.rs +++ b/src/metadata/group.rs @@ -11,9 +11,9 @@ use super::{ /// Represents a group to which plugin metadata objects can belong. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Group { - name: String, - description: Option, - after_groups: Vec, + name: Box, + description: Option>, + after_groups: Box<[String]>, } impl Group { @@ -21,7 +21,7 @@ impl Group { #[must_use] pub fn new(name: String) -> Self { Self { - name, + name: name.into_boxed_str(), ..Default::default() } } @@ -55,7 +55,7 @@ impl Group { /// Set a description for the group. pub fn set_description(&mut self, description: String) -> &mut Self { - self.description = Some(description); + self.description = Some(description.into_boxed_str()); self } @@ -66,7 +66,7 @@ impl Group { /// Set the names of the groups that this group loads after. pub fn set_after_groups(&mut self, after_groups: Vec) -> &mut Self { - self.after_groups = after_groups; + self.after_groups = after_groups.into_boxed_slice(); self } } @@ -77,7 +77,7 @@ impl std::default::Default for Group { #[must_use] fn default() -> Self { Self { - name: Group::DEFAULT_NAME.to_string(), + name: Group::DEFAULT_NAME.into(), description: Default::default(), after_groups: Default::default(), } @@ -96,8 +96,8 @@ impl TryFromYaml for Group { let after = get_strings_vec_value(hash, "after", YamlObjectType::Group)?; Ok(Group { - name: name.to_string(), - description: description.map(|d| d.1.to_string()), + name: name.into(), + description: description.map(|d| d.1.into()), after_groups: after.iter().map(|a| a.to_string()).collect(), }) } diff --git a/src/metadata/location.rs b/src/metadata/location.rs index dcbb88d4..67f0faf2 100644 --- a/src/metadata/location.rs +++ b/src/metadata/location.rs @@ -8,8 +8,8 @@ use super::{ /// Represents a URL at which the parent plugin can be found. #[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Location { - url: String, - name: Option, + url: Box, + name: Option>, } impl Location { @@ -17,7 +17,7 @@ impl Location { #[must_use] pub fn new(url: String) -> Self { Location { - url, + url: url.into_boxed_str(), ..Default::default() } } @@ -41,7 +41,7 @@ impl Location { /// Set a name for the URL, eg. the page or site name. pub fn set_name(&mut self, name: String) -> &mut Self { - self.name = Some(name); + self.name = Some(name.into_boxed_str()); self } } @@ -50,7 +50,7 @@ impl TryFromYaml for Location { fn try_from_yaml(value: &MarkedYaml) -> Result { match &value.data { YamlData::String(s) => Ok(Location { - url: s.clone(), + url: s.clone().into_boxed_str(), name: None, }), YamlData::Hash(h) => { @@ -68,8 +68,8 @@ impl TryFromYaml for Location { )?; Ok(Location { - url: link.to_string(), - name: Some(name.to_string()), + url: link.into(), + name: Some(name.into()), }) } _ => Err(ParseMetadataError::unexpected_type( diff --git a/src/metadata/message.rs b/src/metadata/message.rs index ddf65138..fd4de675 100644 --- a/src/metadata/message.rs +++ b/src/metadata/message.rs @@ -43,8 +43,8 @@ impl std::fmt::Display for MessageType { /// Represents a message's localised text content. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct MessageContent { - text: String, - language: String, + text: Box, + language: Box, } impl MessageContent { @@ -56,7 +56,7 @@ impl MessageContent { #[must_use] pub fn new(text: String) -> Self { MessageContent { - text, + text: text.into_boxed_str(), ..Default::default() } } @@ -80,7 +80,7 @@ impl MessageContent { /// Set the language code to the given value. pub fn set_language(&mut self, language: String) -> &mut Self { - self.language = language; + self.language = language.into_boxed_str(); self } } @@ -128,10 +128,10 @@ pub fn select_message_content<'a>( let mut english = None; for mc in content { - if mc.language == language { + if mc.language.as_ref() == language { return Some(mc); } else if matched.is_none() { - if language_code.is_some_and(|c| c == mc.language) { + if language_code.is_some_and(|c| c == mc.language.as_ref()) { matched = Some(mc); } else if language_code.is_none() { if let Some((content_language_code, _)) = mc.language.split_once('_') { @@ -141,7 +141,7 @@ pub fn select_message_content<'a>( } } - if mc.language == MessageContent::DEFAULT_LANGUAGE { + if mc.language.as_ref() == MessageContent::DEFAULT_LANGUAGE { english = Some(mc); } } @@ -161,8 +161,8 @@ pub fn select_message_content<'a>( #[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Message { message_type: MessageType, - content: Vec, - condition: Option, + content: Box<[MessageContent]>, + condition: Option>, } impl Message { @@ -172,7 +172,7 @@ impl Message { pub fn new(message_type: MessageType, content: String) -> Self { Self { message_type, - content: vec![MessageContent::new(content)], + content: Box::new([MessageContent::new(content)]), condition: None, } } @@ -188,7 +188,7 @@ impl Message { Ok(Self { message_type, - content, + content: content.into_boxed_slice(), condition: None, }) } @@ -217,7 +217,7 @@ impl Message { /// Set the condition string. pub fn set_condition(&mut self, condition: String) -> &mut Self { - self.condition = Some(condition); + self.condition = Some(condition.into_boxed_str()); self } } @@ -228,7 +228,7 @@ pub(crate) fn validate_message_contents( if contents.len() > 1 { let english_string_exists = contents .iter() - .any(|c| c.language == MessageContent::DEFAULT_LANGUAGE); + .any(|c| c.language.as_ref() == MessageContent::DEFAULT_LANGUAGE); if !english_string_exists { return Err(MultilingualMessageContentsError {}); @@ -249,8 +249,8 @@ impl TryFromYaml for MessageContent { get_required_string_value(value.span.start, hash, "lang", YamlObjectType::Message)?; Ok(MessageContent { - text: text.to_string(), - language: language.to_string(), + text: text.into(), + language: language.into(), }) } } @@ -259,15 +259,13 @@ pub(crate) fn parse_message_contents_yaml( value: &MarkedYaml, key: &'static str, parent_yaml_type: YamlObjectType, -) -> Result, ParseMetadataError> { - let mut contents = match &value.data { - YamlData::String(s) => { - vec![MessageContent::new(s.clone())] - } +) -> Result, ParseMetadataError> { + let contents = match &value.data { + YamlData::String(s) => Box::new([MessageContent::new(s.clone())]), YamlData::Array(a) => a .iter() .map(MessageContent::try_from_yaml) - .collect::, _>>()?, + .collect::, _>>()?, _ => { return Err(ParseMetadataError::unexpected_value_type( value.span.start, @@ -278,8 +276,6 @@ pub(crate) fn parse_message_contents_yaml( } }; - contents.shrink_to_fit(); - if validate_message_contents(&contents).is_err() { Err(ParseMetadataError::new( value.span.start, @@ -342,7 +338,7 @@ impl TryFromYaml for Message { }); if let Cow::Owned(text) = result { - mc.text = text; + mc.text = text.into_boxed_str(); } } @@ -356,7 +352,7 @@ impl TryFromYaml for Message { )); } - mc.text = mc.text.replace(&placeholder, sub); + mc.text = mc.text.replace(&placeholder, sub).into_boxed_str(); } if let Ok(Some(m)) = FMT_REGEX.find(&mc.text) { diff --git a/src/metadata/plugin_cleaning_data.rs b/src/metadata/plugin_cleaning_data.rs index ef09b09c..24392e4a 100644 --- a/src/metadata/plugin_cleaning_data.rs +++ b/src/metadata/plugin_cleaning_data.rs @@ -20,8 +20,8 @@ pub struct PluginCleaningData { itm_count: u32, deleted_reference_count: u32, deleted_navmesh_count: u32, - cleaning_utility: String, - detail: Vec, + cleaning_utility: Box, + detail: Box<[MessageContent]>, } impl PluginCleaningData { @@ -32,7 +32,7 @@ impl PluginCleaningData { pub fn new(crc: u32, cleaning_utility: String) -> Self { Self { crc, - cleaning_utility, + cleaning_utility: cleaning_utility.into_boxed_str(), ..Default::default() } } @@ -131,7 +131,7 @@ impl PluginCleaningData { detail: Vec, ) -> Result<&mut Self, MultilingualMessageContentsError> { validate_message_contents(&detail)?; - self.detail = detail; + self.detail = detail.into_boxed_slice(); Ok(self) } } @@ -166,7 +166,7 @@ impl TryFromYaml for PluginCleaningData { Some(n) => { parse_message_contents_yaml(n, "detail", YamlObjectType::PluginCleaningData)? } - None => Vec::new(), + None => Box::default(), }; Ok(PluginCleaningData { @@ -174,7 +174,7 @@ impl TryFromYaml for PluginCleaningData { itm_count: itm, deleted_reference_count: udr, deleted_navmesh_count: nav, - cleaning_utility: util.to_string(), + cleaning_utility: util.into(), detail, }) } diff --git a/src/metadata/plugin_metadata.rs b/src/metadata/plugin_metadata.rs index bdb48856..1368d583 100644 --- a/src/metadata/plugin_metadata.rs +++ b/src/metadata/plugin_metadata.rs @@ -24,15 +24,15 @@ pub(crate) const GHOST_FILE_EXTENSION: &str = ".ghost"; #[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct PluginMetadata { name: PluginName, - group: Option, - load_after: Vec, - requirements: Vec, - incompatibilities: Vec, - messages: Vec, - tags: Vec, - dirty_info: Vec, - clean_info: Vec, - locations: Vec, + group: Option>, + load_after: Box<[File]>, + requirements: Box<[File]>, + incompatibilities: Box<[File]>, + messages: Box<[Message]>, + tags: Box<[Tag]>, + dirty_info: Box<[PluginCleaningData]>, + clean_info: Box<[PluginCleaningData]>, + locations: Box<[Location]>, } impl PluginMetadata { @@ -99,7 +99,7 @@ impl PluginMetadata { /// Set the plugin's group. pub fn set_group(&mut self, group: String) { - self.group = Some(group) + self.group = Some(group.into_boxed_str()) } /// Unsets the plugin's group, so that it is implicitly a member of the @@ -110,42 +110,42 @@ impl PluginMetadata { /// Get the plugins that the plugin must load after. pub fn set_load_after_files(&mut self, files: Vec) { - self.load_after = files; + self.load_after = files.into_boxed_slice(); } /// Get the files that the plugin requires to be installed. pub fn set_requirements(&mut self, files: Vec) { - self.requirements = files; + self.requirements = files.into_boxed_slice(); } /// Get the files that the plugin is incompatible with. pub fn set_incompatibilities(&mut self, files: Vec) { - self.incompatibilities = files; + self.incompatibilities = files.into_boxed_slice(); } /// Get the plugin's messages. pub fn set_messages(&mut self, messages: Vec) { - self.messages = messages; + self.messages = messages.into_boxed_slice(); } /// Get the plugin's Bash Tag suggestions. pub fn set_tags(&mut self, tags: Vec) { - self.tags = tags; + self.tags = tags.into_boxed_slice(); } /// Get the plugin's dirty plugin information. pub fn set_dirty_info(&mut self, dirty_info: Vec) { - self.dirty_info = dirty_info; + self.dirty_info = dirty_info.into_boxed_slice(); } /// Get the plugin's clean plugin information. pub fn set_clean_info(&mut self, clean_info: Vec) { - self.clean_info = clean_info; + self.clean_info = clean_info.into_boxed_slice(); } /// Get the locations at which this plugin can be found. pub fn set_locations(&mut self, locations: Vec) { - self.locations = locations; + self.locations = locations.into_boxed_slice(); } /// Merge metadata from the given [PluginMetadata] object into this object. @@ -162,14 +162,21 @@ impl PluginMetadata { self.group = plugin.group.clone(); } - merge_vecs(&mut self.load_after, &plugin.load_after); - merge_vecs(&mut self.requirements, &plugin.requirements); - merge_vecs(&mut self.incompatibilities, &plugin.incompatibilities); - merge_vecs(&mut self.tags, &plugin.tags); - self.messages.extend(plugin.messages.iter().cloned()); - merge_vecs(&mut self.dirty_info, &plugin.dirty_info); - merge_vecs(&mut self.clean_info, &plugin.clean_info); - merge_vecs(&mut self.locations, &plugin.locations); + merge_slices(&mut self.load_after, &plugin.load_after); + merge_slices(&mut self.requirements, &plugin.requirements); + merge_slices(&mut self.incompatibilities, &plugin.incompatibilities); + merge_slices(&mut self.tags, &plugin.tags); + + self.messages = self + .messages + .iter() + .chain(plugin.messages.iter()) + .cloned() + .collect(); + + merge_slices(&mut self.dirty_info, &plugin.dirty_info); + merge_slices(&mut self.clean_info, &plugin.clean_info); + merge_slices(&mut self.locations, &plugin.locations); } /// Check if no plugin metadata is set. @@ -214,13 +221,13 @@ impl PluginMetadata { #[derive(Clone, Debug, Default)] struct PluginName { - string: String, + string: Box, regex: Option, } impl PluginName { fn new(name: &str) -> Result> { - let name = trim_dot_ghost(name).to_string(); + let name: Box = trim_dot_ghost(name).into(); if is_regex_name(&name) { let non_capturing_name = replace_capturing_groups(&name); @@ -245,7 +252,7 @@ impl PluginName { logging::error!("Encountered an error while trying to match the regex {} to the string {}: {}", regex.as_str(), other_name, e); }).unwrap_or(false) } else { - unicase::eq(self.string.as_str(), other_name) + unicase::eq(self.string.as_ref(), other_name) } } @@ -307,13 +314,15 @@ fn is_regex_name(name: &str) -> bool { name.contains(|c| ":\\*?|".chars().any(|n| c == n)) } -fn merge_vecs(target: &mut Vec, source: &[T]) { - let initial_target_len = target.len(); +fn merge_slices(target: &mut Box<[T]>, source: &[T]) { + let mut vec = target.to_vec(); for element in source { - if !target[..initial_target_len].contains(element) { - target.push(element.clone()) + if !target.contains(element) { + vec.push(element.clone()) } } + + *target = vec.into_boxed_slice() } fn replace_capturing_groups(regex_string: &str) -> Cow<'_, str> { @@ -375,18 +384,18 @@ impl TryFromYaml for PluginMetadata { let group = get_string_value(hash, "group", YamlObjectType::PluginMetadata)?; - let load_after = get_vec(hash, "after")?; - let requirements = get_vec(hash, "req")?; - let incompatibilities = get_vec(hash, "inc")?; - let messages = get_vec(hash, "msg")?; - let tags = get_vec(hash, "tag")?; - let dirty_info = get_vec(hash, "dirty")?; - let clean_info = get_vec(hash, "clean")?; - let locations = get_vec(hash, "url")?; + let load_after = get_boxed_slice(hash, "after")?; + let requirements = get_boxed_slice(hash, "req")?; + let incompatibilities = get_boxed_slice(hash, "inc")?; + let messages = get_boxed_slice(hash, "msg")?; + let tags = get_boxed_slice(hash, "tag")?; + let dirty_info = get_boxed_slice(hash, "dirty")?; + let clean_info = get_boxed_slice(hash, "clean")?; + let locations = get_boxed_slice(hash, "url")?; Ok(PluginMetadata { name, - group: group.map(|g| g.1.to_string()), + group: group.map(|g| g.1.into()), load_after, requirements, incompatibilities, @@ -399,18 +408,14 @@ impl TryFromYaml for PluginMetadata { } } -fn get_vec( +fn get_boxed_slice( hash: &saphyr::AnnotatedHash, key: &'static str, -) -> Result, ParseMetadataError> { - let mut vec = get_as_slice(hash, key, YamlObjectType::PluginMetadata)? +) -> Result, ParseMetadataError> { + get_as_slice(hash, key, YamlObjectType::PluginMetadata)? .iter() .map(|e| T::try_from_yaml(e)) - .collect::, _>>()?; - - vec.shrink_to_fit(); - - Ok(vec) + .collect() } impl EmitYaml for PluginMetadata { diff --git a/src/metadata/tag.rs b/src/metadata/tag.rs index b9276c36..b3db1d13 100644 --- a/src/metadata/tag.rs +++ b/src/metadata/tag.rs @@ -19,9 +19,9 @@ pub enum TagSuggestion { /// Represents a Bash Tag suggestion for a plugin. #[derive(Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Tag { - name: String, + name: Box, suggestion: TagSuggestion, - condition: Option, + condition: Option>, } impl Tag { @@ -29,7 +29,7 @@ impl Tag { #[must_use] pub fn new(name: String, suggestion: TagSuggestion) -> Self { Self { - name, + name: name.into_boxed_str(), suggestion, condition: None, } @@ -59,7 +59,7 @@ impl Tag { /// Set the condition string. pub fn set_condition(&mut self, condition: String) -> &mut Self { - self.condition = Some(condition); + self.condition = Some(condition.into_boxed_str()); self } } @@ -97,11 +97,11 @@ impl TryFromYaml for Tag { } } -fn name_and_suggestion(value: &str) -> (String, TagSuggestion) { +fn name_and_suggestion(value: &str) -> (Box, TagSuggestion) { if let Some(name) = value.strip_prefix("-") { - (name.to_string(), TagSuggestion::Removal) + (name.into(), TagSuggestion::Removal) } else { - (value.to_string(), TagSuggestion::Addition) + (value.into(), TagSuggestion::Addition) } } diff --git a/src/metadata/yaml/emit.rs b/src/metadata/yaml/emit.rs index 33eb6266..01f94dd0 100644 --- a/src/metadata/yaml/emit.rs +++ b/src/metadata/yaml/emit.rs @@ -331,6 +331,12 @@ impl EmitYaml for Vec { } } +impl EmitYaml for Box<[T]> { + fn emit_yaml(&self, emitter: &mut YamlEmitter) { + self.as_ref().emit_yaml(emitter); + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/metadata/yaml/parse.rs b/src/metadata/yaml/parse.rs index 8b426887..9318cd15 100644 --- a/src/metadata/yaml/parse.rs +++ b/src/metadata/yaml/parse.rs @@ -110,7 +110,7 @@ pub fn get_strings_vec_value<'a>( ExpectedType::String, )), }) - .collect::, _>>(), + .collect(), None => Err(ParseMetadataError::unexpected_value_type( n.span.start, key, @@ -180,14 +180,14 @@ pub fn get_as_slice<'a>( pub fn parse_condition( hash: &saphyr::AnnotatedHash, yaml_type: YamlObjectType, -) -> Result, ParseMetadataError> { +) -> Result>, ParseMetadataError> { match get_string_value(hash, "condition", yaml_type)? { Some((marker, s)) => { let s = s.to_string(); if let Err(e) = Expression::from_str(&s) { return Err(ParseMetadataError::invalid_condition(marker, s, e)); } - Ok(Some(s)) + Ok(Some(s.into_boxed_str())) } None => Ok(None), } diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index d829450b..178f7619 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -48,8 +48,8 @@ pub struct Plugin { game_type: GameType, crc: Option, version: Option, - tags: Vec, - archive_paths: Vec, + tags: Box<[String]>, + archive_paths: Box<[PathBuf]>, archive_assets: BTreeMap>, } @@ -70,8 +70,8 @@ impl Plugin { }; let mut version = None; - let mut tags = Vec::new(); - let mut archive_paths = Vec::new(); + let mut tags = Box::default(); + let mut archive_paths = Box::default(); let mut archive_assets = BTreeMap::new(); let plugin = if game_type != GameType::OpenMW || !has_ascii_extension(plugin_path, "omwscripts") { @@ -79,11 +79,12 @@ impl Plugin { plugin.parse_file(parse_options)?; if let Some(description) = plugin.description()? { - tags = extract_bash_tags(&description); + tags = extract_bash_tags(&description).into_boxed_slice(); version = extract_version(&description)?; } - archive_paths = find_associated_archives(game_type, game_cache, plugin_path); + archive_paths = + find_associated_archives(game_type, game_cache, plugin_path).into_boxed_slice(); if load_scope == LoadScope::WholePlugin { archive_assets = assets_in_archives(&archive_paths); diff --git a/src/sorting/groups.rs b/src/sorting/groups.rs index feba93b6..66bde9a0 100644 --- a/src/sorting/groups.rs +++ b/src/sorting/groups.rs @@ -21,7 +21,7 @@ use super::{ error::GroupsPathError, }; -pub type GroupsGraph = Graph; +pub type GroupsGraph = Graph, EdgeType>; pub fn build_groups_graph( masterlist_groups: &[Group], @@ -49,7 +49,7 @@ pub fn build_groups_graph( EdgeType::UserLoadAfter, )?; - if let Some(cycle) = find_cycle(&graph, |node| node.clone()) { + if let Some(cycle) = find_cycle(&graph, |node| node.clone().into_string()) { Err(CyclicInteractionError::new(cycle).into()) } else { Ok(graph) @@ -72,7 +72,7 @@ fn add_groups<'a>( for group in groups { let key = group.name(); if !group_nodes.contains_key(key) { - let node_index = graph.add_node(group.name().to_string()); + let node_index = graph.add_node(group.name().into()); group_nodes.insert(key, node_index); } } @@ -114,7 +114,7 @@ pub fn find_path( from_group_name: &str, to_group_name: &str, ) -> Result, GroupsPathError> { - let float_graph: Graph<&String, f32> = graph.map( + let float_graph: Graph<&Box, f32> = graph.map( |_, n| n, |_, e| { if *e == EdgeType::UserLoadAfter { @@ -132,7 +132,7 @@ pub fn find_path( let paths = bellman_ford(&float_graph, from_vertex).map_err(|_| PathfindingError::NegativeCycle)?; - let mut path = vec![Vertex::new(graph[to_vertex].clone())]; + let mut path = vec![Vertex::new(graph[to_vertex].clone().into_string())]; let mut current = to_vertex; while current != from_vertex { let preceding_vertex = match paths.predecessors.get(current.index()) { @@ -147,7 +147,10 @@ pub fn find_path( return Ok(Vec::new()); } _ => { - return Err(PathfindingError::PrecedingNodeNotFound(graph[current].clone()).into()); + return Err(PathfindingError::PrecedingNodeNotFound( + graph[current].clone().into_string(), + ) + .into()); } }; @@ -164,14 +167,15 @@ pub fn find_path( Some(e) => e, None => { return Err(PathfindingError::EdgeNotFound { - from_group: graph[*preceding_vertex].clone(), - to_group: graph[current].clone(), + from_group: graph[*preceding_vertex].clone().into_string(), + to_group: graph[current].clone().into_string(), } .into()); } }; - let vertex = Vertex::new(graph[*preceding_vertex].clone()).with_out_edge_type(graph[edge]); + let vertex = Vertex::new(graph[*preceding_vertex].clone().into_string()) + .with_out_edge_type(graph[edge]); path.push(vertex); current = *preceding_vertex; @@ -183,13 +187,15 @@ pub fn find_path( } fn find_node_by_weight( - graph: &Graph, + graph: &Graph, EdgeType>, weight: &str, ) -> Result { - match graph - .node_indices() - .find(|i| graph.node_weight(*i).map(|w| *w == weight).unwrap_or(false)) - { + match graph.node_indices().find(|i| { + graph + .node_weight(*i) + .map(|w| w.as_ref() == weight) + .unwrap_or(false) + }) { Some(n) => Ok(n), None => { logging::error!("Can't find group with name {}", weight); @@ -267,7 +273,7 @@ impl<'a> DfsVisitor<'a> for GroupsPathLengthVisitor { pub fn get_default_group_node(graph: &GroupsGraph) -> Result { graph .node_indices() - .find(|n| graph[*n] == Group::DEFAULT_NAME) + .find(|n| graph[*n].as_ref() == Group::DEFAULT_NAME) .ok_or_else(|| UndefinedGroupError::new(Group::DEFAULT_NAME.to_string())) } diff --git a/src/sorting/plugins.rs b/src/sorting/plugins.rs index 9b5a190b..57c393d7 100644 --- a/src/sorting/plugins.rs +++ b/src/sorting/plugins.rs @@ -32,12 +32,12 @@ pub struct PluginSortingData<'a, T: SortingPlugin> { load_order_index: usize, - pub(super) group: String, + pub(super) group: Box, group_is_user_metadata: bool, - pub(super) masterlist_load_after: Vec, - pub(super) user_load_after: Vec, - pub(super) masterlist_req: Vec, - pub(super) user_req: Vec, + pub(super) masterlist_load_after: Box<[String]>, + pub(super) user_load_after: Box<[String]>, + pub(super) masterlist_req: Box<[String]>, + pub(super) user_req: Box<[String]>, } impl<'a, T: SortingPlugin> PluginSortingData<'a, T> { @@ -58,7 +58,7 @@ impl<'a, T: SortingPlugin> PluginSortingData<'a, T> { .and_then(|m| m.group()) .or_else(|| masterlist_metadata.and_then(|m| m.group())) .unwrap_or(Group::DEFAULT_NAME) - .to_string(), + .into(), group_is_user_metadata: user_metadata.and_then(|m| m.group()).is_some(), masterlist_load_after: masterlist_metadata .map(|m| to_filenames(m.load_after_files())) @@ -141,7 +141,7 @@ impl SortingPlugin for Plugin { } } -fn to_filenames(files: &[File]) -> Vec { +fn to_filenames(files: &[File]) -> Box<[String]> { files .iter() .map(|f| f.name().as_str().to_string()) @@ -987,8 +987,8 @@ struct PathCacher<'a> { fn get_plugins_in_groups( graph: &InnerPluginsGraph, -) -> HashMap> { - let mut plugins_in_groups: HashMap> = HashMap::default(); +) -> HashMap, Vec> { + let mut plugins_in_groups: HashMap, Vec> = HashMap::default(); for node in graph.node_indices() { let group_name = graph[node].group.clone(); @@ -1047,7 +1047,7 @@ type GroupNodeIndex = NodeIndex; struct GroupsPathVisitor<'a, 'b, 'c, 'd, 'e, T: SortingPlugin> { plugins_graph: &'a mut PluginsGraph<'b, T>, groups_graph: &'e GroupsGraph, - groups_plugins: &'c HashMap>, + groups_plugins: &'c HashMap, Vec>, finished_group_vertices: &'d mut HashSet, group_node_to_ignore_as_source: Option, edge_stack: Vec<(EdgeReference<'e, EdgeType>, &'c [PluginNodeIndex])>, @@ -1058,7 +1058,7 @@ impl<'a, 'b, 'c, 'd, 'e, T: SortingPlugin> GroupsPathVisitor<'a, 'b, 'c, 'd, 'e, fn new( plugins_graph: &'a mut PluginsGraph<'b, T>, groups_graph: &'e GroupsGraph, - groups_plugins: &'c HashMap>, + groups_plugins: &'c HashMap, Vec>, finished_group_vertices: &'d mut HashSet, group_node_to_ignore_as_source: Option, ) -> Self { @@ -1080,7 +1080,7 @@ impl<'a, 'b, 'c, 'd, 'e, T: SortingPlugin> GroupsPathVisitor<'a, 'b, 'c, 'd, 'e, fn find_plugins_in_group(&self, node_index: GroupNodeIndex) -> &'c [PluginNodeIndex] { self.groups_plugins - .get(&self.groups_graph[node_index]) + .get(self.groups_graph[node_index].as_ref()) .map(|v| v.as_slice()) .unwrap_or_default() } @@ -3269,7 +3269,7 @@ mod tests { let fixture = Fixture::with_plugins(&[PLUGIN_A, PLUGIN_B]); let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_load_after = vec![PLUGIN_B.into()]; + a.masterlist_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3285,7 +3285,7 @@ mod tests { let fixture = Fixture::with_plugins(&[PLUGIN_A, PLUGIN_B]); let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_req = vec![PLUGIN_B.into()]; + a.masterlist_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3381,7 +3381,7 @@ mod tests { fixture.get_plugin_mut(PLUGIN_A).is_master = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_load_after = vec![PLUGIN_B.into()]; + a.masterlist_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3407,7 +3407,7 @@ mod tests { fixture.get_plugin_mut(PLUGIN_A).is_master = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_load_after = vec![PLUGIN_B.into()]; + a.user_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3433,7 +3433,7 @@ mod tests { fixture.get_plugin_mut(PLUGIN_A).is_master = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_req = vec![PLUGIN_B.into()]; + a.masterlist_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3459,7 +3459,7 @@ mod tests { fixture.get_plugin_mut(PLUGIN_A).is_master = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_req = vec![PLUGIN_B.into()]; + a.user_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3560,7 +3560,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_load_after = vec![PLUGIN_B.into()]; + a.masterlist_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3590,7 +3590,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_load_after = vec![PLUGIN_B.into()]; + a.masterlist_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3621,7 +3621,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_load_after = vec![PLUGIN_B.into()]; + a.user_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3650,7 +3650,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_load_after = vec![PLUGIN_B.into()]; + a.user_load_after = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3681,7 +3681,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_req = vec![PLUGIN_B.into()]; + a.masterlist_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3711,7 +3711,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.masterlist_req = vec![PLUGIN_B.into()]; + a.masterlist_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3742,7 +3742,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_req = vec![PLUGIN_B.into()]; + a.user_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; @@ -3771,7 +3771,7 @@ mod tests { b.is_blueprint_plugin = true; let mut a = fixture.sorting_data(PLUGIN_A); - a.user_req = vec![PLUGIN_B.into()]; + a.user_req = Box::new([PLUGIN_B.into()]); let data = vec![a, fixture.sorting_data(PLUGIN_B)]; diff --git a/src/sorting/validate.rs b/src/sorting/validate.rs index e2b193f1..f8caa7d6 100644 --- a/src/sorting/validate.rs +++ b/src/sorting/validate.rs @@ -16,14 +16,14 @@ pub fn validate_plugin_groups( plugins_sorting_data: &[PluginSortingData<'_, T>], groups_graph: &GroupsGraph, ) -> Result<(), UndefinedGroupError> { - let group_names: HashSet<&String> = groups_graph + let group_names: HashSet<&str> = groups_graph .node_indices() - .map(|i| &groups_graph[i]) + .map(|i| groups_graph[i].as_ref()) .collect(); for plugin in plugins_sorting_data { - if !group_names.contains(&plugin.group) { - return Err(UndefinedGroupError::new(plugin.group.clone())); + if !group_names.contains(plugin.group.as_ref()) { + return Err(UndefinedGroupError::new(plugin.group.clone().into_string())); } }