feat: update highlevel parse
This commit is contained in:
@@ -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<ProgramStr>,
|
||||
icon: Rc<ProgramIcon>,
|
||||
behavior: Rc<ProgramBehavior>,
|
||||
name: Option<Rc<ProgramStr>>,
|
||||
icon: Option<Rc<ProgramIcon>>,
|
||||
behavior: Option<Rc<ProgramBehavior>>,
|
||||
|
||||
strs: Vec<Rc<ProgramStr>>,
|
||||
icons: Vec<Rc<ProgramIcon>>,
|
||||
@@ -215,6 +219,36 @@ impl Program {
|
||||
.ok_or(ParseProgramError::NoDirNamePart)
|
||||
}
|
||||
|
||||
fn flat_hashmap<V, U, F>(
|
||||
hashmap: &HashMap<String, V>,
|
||||
f: F,
|
||||
) -> Result<(Vec<U>, HashMap<String, usize>), ParseProgramError>
|
||||
where
|
||||
F: Fn(&V) -> Result<U, ParseProgramError>,
|
||||
{
|
||||
let mut indexmap: HashMap<String, usize> = HashMap::with_capacity(hashmap.len());
|
||||
let mut vector: Vec<U> = 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<T>(
|
||||
key: &String,
|
||||
vector: &Vec<Rc<T>>,
|
||||
index_map: &HashMap<String, usize>,
|
||||
) -> Result<Rc<T>, 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<Self, ParseProgramError> {
|
||||
// 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<ProgramProgIdKey>
|
||||
assoc: Rc<ProgramProgIdKey>,
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
Reference in New Issue
Block a user