z_mirror/fmm
git clone https://git.raiguard.me/z_mirror/fmm
67c3f36
dependencies
1use itertools:: Itertools ; 2use once_cell:: sync:: OnceCell ; 3use regex:: Regex ; 4use semver:: VersionReq ; 5use thiserror:: Error ; 6 7# [ derive ( Debug , PartialEq )] 8pub struct ModDependency { 9pub dep_type : ModDependencyType , 10pub name : String , 11pub version_req : Option < VersionReq >, 12} 13 14impl ModDependency { 15pub fn new ( input : & String ) ->Result < Self , ModDependencyErr > { 16// Avoid creating the regex object every time 17static DEP_STRING_REGEX : OnceCell < Regex > =OnceCell :: new (); 18let captures =DEP_STRING_REGEX 19. get_or_init ( ||{ 20Regex :: new ( 21r"^(?:(?P<type>[!?~]|\(\?\)) *)?(?P<name>(?: *[a-zA-Z0-9_-]+)+(?: *$)?)(?: *(?P<version_req>[<>=]=?) *(?P<version>(?:\d+\.){1,2}\d+))?$" , 22). unwrap () 23}) 24. captures ( input) 25. ok_or ( ModDependencyErr :: InvalidDependencyString ( input. clone ())) ?; 26 27Ok ( Self { 28dep_type : match captures. name ( "type" ). map ( |mtch| mtch. as_str ()) { 29None =>ModDependencyType :: Required , 30Some ( "!" ) =>ModDependencyType :: Incompatible , 31Some ( "~" ) =>ModDependencyType :: NoLoadOrder , 32Some ( "?" ) =>ModDependencyType :: Optional , 33Some ( "(?)" ) =>ModDependencyType :: OptionalHidden , 34Some ( str) =>return Err ( ModDependencyErr :: UnknownModifier ( str. to_string ())), 35}, 36name : match captures. name ( "name" ) { 37Some ( mtch) => mtch. as_str (). to_string (), 38None =>return Err ( ModDependencyErr :: NameIsUnparsable ( input. clone ())), 39}, 40version_req : match [ captures. name ( "version_req" ), captures. name ( "version" )] { 41[ Some ( req_match), Some ( version_match)] =>{ 42// Factorio does not sanitize leading zeros, so we must do it ourselves 43let version_str = version_match. as_str (); 44let sanitized = version_str 45. split ( '.' ) 46. map ( |sub|{ 47Ok ( sub 48. parse ::< usize >() 49. map_err ( |_|{ 50ModDependencyErr :: InvalidDependencyString ( input. clone ()) 51}) ? 52. to_string ()) 53}) 54. intersperse ( Ok ( "." . to_string ())) 55. collect ::< Result < String , ModDependencyErr >>() ?; 56 57// Assemble version req from parts 58let mut version_req =String :: new (); 59 version_req. push_str ( req_match. as_str ()); 60 version_req. push ( ' ' ); 61 version_req. push_str ( & sanitized); 62 63match VersionReq :: parse ( & version_req) { 64Ok ( version_req) =>Some ( version_req), 65Err ( _) =>{ 66return Err ( ModDependencyErr :: InvalidVersionReq ( 67 req_match. as_str (). to_string (), 68)) 69} 70} 71} 72 _ =>None , 73}, 74}) 75} 76} 77 78# [ derive ( Debug , PartialEq )] 79pub enum ModDependencyType { 80Incompatible , 81NoLoadOrder , 82Optional , 83OptionalHidden , 84Required , 85} 86 87pub type ModDependencyResult =Result < Vec < ModDependency >, ModDependencyErr >; 88 89# [ derive ( Clone , Debug , Error )] 90pub enum ModDependencyErr { 91# [ error ( "Invalid dependency string: `{0}`" )] 92InvalidDependencyString ( String ), 93# [ error ( "Invalid dependency version requirement: `{0}`" )] 94InvalidVersionReq ( String ), 95# [ error ( "Dependency name could not be parsed: `{0}`" )] 96NameIsUnparsable ( String ), 97# [ error ( "Unknown dependency modifier: `{0}`" )] 98UnknownModifier ( String ), 99}