diff --git a/wfassoc/src/highlevel.rs b/wfassoc/src/highlevel.rs index 66312bc..f185c0e 100644 --- a/wfassoc/src/highlevel.rs +++ b/wfassoc/src/highlevel.rs @@ -1,8 +1,8 @@ -use crate::{lowlevel, utilities, win32}; +use crate::{lowlevel, utilities, win32::concept}; use std::collections::HashMap; use std::ffi::OsStr; -use std::rc::Rc; use std::path::Path; +use std::rc::Rc; use thiserror::Error as TeError; pub use lowlevel::{Scope, View}; @@ -20,13 +20,17 @@ pub enum SchemaError { #[derive(Debug, TeError)] pub enum ParseProgramError { #[error("{0}")] - BadFileName(#[from] win32::concept::BadFileNameError), + BadFileName(#[from] concept::BadFileNameError), + #[error("{0}")] + ParseCmdLine(#[from] concept::ParseCmdLineError), #[error("{0}")] CastOsStr(#[from] utilities::CastOsStrError), #[error("given path doesn't has legal file name part")] NoFileNamePart, #[error("given path doesn't has legal directory part")] NoDirNamePart, + #[error("given identifier is not presented in dict")] + NoSuchIdentifier, } /// Error occurs when operating with `Program`. @@ -177,9 +181,9 @@ pub struct Program { applications_key: lowlevel::ApplicationsKey, file_name: String, dir_name: String, - name: Rc, - icon: Rc, - behavior: Rc, + name: Option>, + icon: Option>, + behavior: Option>, strs: Vec>, icons: Vec>, @@ -215,6 +219,36 @@ impl Program { .ok_or(ParseProgramError::NoDirNamePart) } + fn flat_hashmap( + hashmap: &HashMap, + f: F, + ) -> Result<(Vec, HashMap), ParseProgramError> + where + F: Fn(&V) -> Result, + { + let mut indexmap: HashMap = HashMap::with_capacity(hashmap.len()); + let mut vector: Vec = Vec::with_capacity(hashmap.len()); + for (key, value) in hashmap.into_iter() { + indexmap.insert(key.clone(), vector.len()); + vector.push(f(value)?); + } + Ok((vector, indexmap)) + } + + fn resolve_index( + key: &String, + vector: &Vec>, + index_map: &HashMap, + ) -> Result, ParseProgramError> { + match index_map.get(key) { + Some(index) => match vector.get(*index) { + Some(value) => Ok(value.clone()), + None => Err(ParseProgramError::NoSuchIdentifier), + }, + None => Err(ParseProgramError::NoSuchIdentifier), + } + } + /// Try creating Program from Schema. pub fn new(schema: Schema) -> Result { // Extract file name part and directory name part respectively. @@ -224,10 +258,52 @@ impl Program { let dir_name = Self::extract_dir_name(schema_path)?; let dir_name = String::from(utilities::osstr_to_str(dir_name)?); // Build app paths key and applications key respectively - let key = win32::concept::FileName::new(&file_name)?; + let key = concept::FileName::new(&file_name)?; let app_paths_key = lowlevel::AppPathsKey::new(key.clone()); let applications_key = lowlevel::ApplicationsKey::new(key.clone()); + // Build string, icon and behavior list, + // and build mapper at the same time. + let (strs, strs_index_map) = Self::flat_hashmap(&schema.strs, |entry| { + let str_res_variant: lowlevel::StrResVariant = entry.as_str().into(); + let program_str = ProgramStr { + inner: str_res_variant, + }; + Ok(Rc::new(program_str)) + })?; + let (icons, icons_index_map) = Self::flat_hashmap(&schema.icons, |entry| { + let icon_res_variant: lowlevel::IconResVariant = entry.as_str().into(); + let program_icon = ProgramIcon { + inner: icon_res_variant, + }; + Ok(Rc::new(program_icon)) + })?; + let (behaviors, behaviors_index_map) = Self::flat_hashmap(&schema.behaviors, |entry| { + // We simply always use "Open" verb. + let cmdline: concept::CmdLine = entry.as_str().parse()?; + let verb = concept::Verb::OPEN.clone(); + let shell_verb = lowlevel::ShellVerb::new(verb, cmdline); + let program_behavior = ProgramBehavior { inner: shell_verb }; + Ok(Rc::new(program_behavior)) + })?; + + // Setup default name, icon and behavior + let name = schema + .name + .map(|name| Self::resolve_index(&name, &strs, &strs_index_map)) + .transpose()?; + let icon = schema + .icon + .map(|icon| Self::resolve_index(&icon, &icons, &icons_index_map)) + .transpose()?; + let behavior = schema + .behavior + .map(|behavior| Self::resolve_index(&behavior, &behaviors, &behaviors_index_map)) + .transpose()?; + + // Process file extensions. + // We need create ProgIds list and Exts list at the same time. + todo!(); // Ok(Self { // app_paths_key, @@ -296,7 +372,7 @@ struct ProgramIcon { /// Internal used enum presenting a Program behavior (command line setups). #[derive(Debug)] struct ProgramBehavior { - inner: win32::concept::CmdLine, + inner: lowlevel::ShellVerb, } /// Internal used struct presenting a Program ProgId. @@ -312,7 +388,7 @@ struct ProgramProgIdKey { #[derive(Debug)] struct ProgramExtKey { key: lowlevel::ExtKey, - assoc: Rc + assoc: Rc, } // endregion