diff --git a/src/main.rs b/src/main.rs index 47b6c15..4222c7b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1120,10 +1120,10 @@ async fn get_file_async(mut path:std::path::PathBuf,file_name:impl AsRef<std::pa }, } } -type QueryResult=Result<tokio::fs::File,QueryResolveError>; -type QueryResultHandle=tokio::task::JoinHandle<QueryResult>; +type QueryHintResult=Result<FileHint,QueryResolveError>; +type QueryResultHandle=tokio::task::JoinHandle<Result<tokio::fs::File,QueryResolveError>>; trait Query{ - async fn resolve(self)->Result<tokio::fs::File,QueryResolveError>; + async fn resolve(self)->QueryHintResult; } struct QuerySingle(QueryResultHandle); impl QuerySingle{ @@ -1132,20 +1132,20 @@ impl QuerySingle{ } } impl Query for QuerySingle{ - async fn resolve(self)->Result<tokio::fs::File,QueryResolveError>{ + async fn resolve(self)->QueryHintResult{ match self.0.await{ - Ok(Ok(file))=>Ok(file), + Ok(Ok(file))=>Ok(FileHint{file,hint:ScriptHint::Undetermined}), Ok(Err(e))=>Err(e), Err(e)=>Err(QueryResolveError::JoinError(e)), } } } -struct QueryTriplet{ +struct QueryTriple{ module:QuerySingle, server:QuerySingle, client:QuerySingle, } -impl QueryTriplet{ +impl QueryTriple{ fn rox_rojo(search_path:&std::path::PathBuf,search_name:&str,search_module:bool)->Self{ //this should be implemented as constructors of Triplet and Quadruplet to fully support Trey's suggestion let module_name=if search_module{ @@ -1159,15 +1159,28 @@ impl QueryTriplet{ client:QuerySingle(tokio::spawn(get_file_async(search_path.clone(),format!("{}.client.lua",search_name)))), } } - fn rojo(search_path:&std::path::PathBuf,search_name:&str,search_module:bool,is_subfolder:bool)->Self{ - if is_subfolder{ - QueryTriplet::rox_rojo(search_path,"init",search_module) - }else{ - QueryTriplet::rox_rojo(search_path,search_name,search_module) - } + fn rojo(search_path:&std::path::PathBuf,search_name:&str)->Self{ + QueryTriple::rox_rojo(search_path,"init",false) } } -fn mega_triple_join(query_triplet:(QueryResult,QueryResult,QueryResult))->QueryResult{ +//these functions can be achieved with macros, but I have not learned that yet +fn mega_double_join(query_pair:(QueryHintResult,QueryHintResult))->QueryHintResult{ + match query_pair{ + //unambiguously locate file + (Ok(f),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Ok(f))=>Ok(f), + //multiple files located + (Ok(_),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Ok(_)) + |(Ok(_),Ok(_))=>Err(QueryResolveError::Ambiguous), + //no files located + (Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound))=>Err(QueryResolveError::NotFound), + //other error + (Err(e),_) + |(_,Err(e))=>Err(e), + } +} +fn mega_triple_join(query_triplet:(QueryHintResult,QueryHintResult,QueryHintResult))->QueryHintResult{ match query_triplet{ //unambiguously locate file (Ok(f),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound)) @@ -1183,16 +1196,73 @@ fn mega_triple_join(query_triplet:(QueryResult,QueryResult,QueryResult))->QueryR //other error (Err(e),_,_) |(_,Err(e),_) - |(_,_,Err(e))=>Err(e) + |(_,_,Err(e))=>Err(e), } } -impl Query for QueryTriplet{ - async fn resolve(self)->Result<tokio::fs::File,QueryResolveError>{ +//LETS GOOOOOOOOOOOOOOOO +fn mega_quadruple_join(query_quad:(QueryHintResult,QueryHintResult,QueryHintResult,QueryHintResult))->QueryHintResult{ + match query_quad{ + //unambiguously locate file + (Ok(f),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Ok(f),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Ok(f),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Ok(f))=>Ok(f), + //multiple files located + (Ok(_),Ok(_),Ok(_),Err(QueryResolveError::NotFound)) + |(Ok(_),Ok(_),Err(QueryResolveError::NotFound),Ok(_)) + |(Ok(_),Ok(_),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound)) + |(Ok(_),Err(QueryResolveError::NotFound),Ok(_),Ok(_)) + |(Ok(_),Err(QueryResolveError::NotFound),Ok(_),Err(QueryResolveError::NotFound)) + |(Ok(_),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Ok(_)) + |(Err(QueryResolveError::NotFound),Ok(_),Ok(_),Ok(_)) + |(Err(QueryResolveError::NotFound),Ok(_),Ok(_),Err(QueryResolveError::NotFound)) + |(Err(QueryResolveError::NotFound),Ok(_),Err(QueryResolveError::NotFound),Ok(_)) + |(Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Ok(_),Ok(_)) + |(Ok(_),Ok(_),Ok(_),Ok(_))=>Err(QueryResolveError::Ambiguous), + //no files located + (Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound),Err(QueryResolveError::NotFound))=>Err(QueryResolveError::NotFound), + //other error + (Err(e),_,_,_) + |(_,Err(e),_,_) + |(_,_,Err(e),_) + |(_,_,_,Err(e))=>Err(e), + } +} +impl Query for QueryTriple{ + async fn resolve(self)->QueryHintResult{ let (module,server,client)=tokio::join!(self.module.0,self.server.0,self.client.0); mega_triple_join(( - module.map_err(|e|QueryResolveError::JoinError(e))?, - server.map_err(|e|QueryResolveError::JoinError(e))?, - client.map_err(|e|QueryResolveError::JoinError(e))?, + module.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::ModuleScript}), + server.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::Script}), + client.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::LocalScript}), + )) + } +} +struct QueryQuad{ + module_implicit:QuerySingle, + module_explicit:QuerySingle, + server:QuerySingle, + client:QuerySingle, +} +impl QueryQuad{ + fn rox_rojo(search_path:&std::path::PathBuf,search_name:&str)->Self{ + let fill=QueryTriple::rox_rojo(search_path,search_name,true); + Self{ + module_implicit:QuerySingle::rox(search_path,search_name),//Script.lua + module_explicit:fill.module,//Script.module.lua + server:fill.server, + client:fill.client, + } + } +} +impl Query for QueryQuad{ + async fn resolve(self)->QueryHintResult{ + let (module_implicit,module_explicit,server,client)=tokio::join!(self.module_implicit.0,self.module_explicit.0,self.server.0,self.client.0); + mega_quadruple_join(( + module_implicit.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::ModuleScript}), + module_explicit.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::ModuleScript}), + server.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::Script}), + client.map_err(|e|QueryResolveError::JoinError(e))?.map(|file|FileHint{file,hint:ScriptHint::LocalScript}), )) } } @@ -1203,25 +1273,23 @@ async fn discern_node(search_path:&std::path::PathBuf,search_name:&str,style:Opt //folder Ok(if let Ok(dir)=tokio::fs::read_dir(contents_folder.as_path()).await{ //scan inside the folder for an object to define the class of the folder - let (script_file,model_file)=tokio::join!( - async {match style{ - Some(DecompileStyle::Rox)=>QuerySingle::rox(&contents_folder,search_name).resolve().await, - Some(DecompileStyle::RoxRojo)=>QueryTriplet::rox_rojo(&contents_folder,search_name,false).resolve().await, - Some(DecompileStyle::Rojo)=>QueryTriplet::rojo(&contents_folder,search_name,false,true).resolve().await, - //try all three and complain if there is ambiguity - None=>mega_triple_join(tokio::join!( - QuerySingle::rox(&contents_folder,search_name).resolve(), - //true=search for module here to avoid ambiguity with QuerySingle::rox results - QueryTriplet::rox_rojo(&contents_folder,search_name,true).resolve(), - QueryTriplet::rojo(&contents_folder,search_name,true,true).resolve(), - )) - }}, - //model files are rox & rox-rojo only, so it's a lot less work... - get_file_async(contents_folder.clone(),format!("{}.rbxmx",search_name)) - ); + let script_query=async {match style{ + Some(DecompileStyle::Rox)=>QuerySingle::rox(&contents_folder,search_name).resolve().await, + Some(DecompileStyle::RoxRojo)=>QueryQuad::rox_rojo(&contents_folder,search_name).resolve().await, + Some(DecompileStyle::Rojo)=>QueryTriple::rojo(&contents_folder,search_name).resolve().await, + //try all three and complain if there is ambiguity + None=>mega_triple_join(tokio::join!( + QuerySingle::rox(&contents_folder,search_name).resolve(), + //true=search for module here to avoid ambiguity with QuerySingle::rox results + QueryTriple::rox_rojo(&contents_folder,search_name,true).resolve(), + QueryTriple::rojo(&contents_folder,search_name).resolve(), + )) + }}; + //model files are rox & rox-rojo only, so it's a lot less work... + let model_query=get_file_async(contents_folder.clone(),format!("{}.rbxmx",search_name)); //model? script? both? - Some(match (script_file,model_file){ - (Ok(mut file),Err(QueryResolveError::NotFound))=>{ + Some(match tokio::join!(script_query,model_query){ + (Ok(FileHint{mut file,hint}),Err(QueryResolveError::NotFound))=>{ //read entire file let mut buf=String::new(); file.read_to_string(&mut buf).await?; @@ -1259,6 +1327,17 @@ async fn discern_node(search_path:&std::path::PathBuf,search_name:&str,style:Opt }) } +enum ScriptHint{ + Script, + LocalScript, + ModuleScript, + Undetermined, +} +struct FileHint{ + file:tokio::fs::File, + hint:ScriptHint, +} + enum CompileClass{ Folder, Script(String),