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::collections::HashMap;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::rc::Rc;
|
||||||
use thiserror::Error as TeError;
|
use thiserror::Error as TeError;
|
||||||
|
|
||||||
pub use lowlevel::{Scope, View};
|
pub use lowlevel::{Scope, View};
|
||||||
@@ -20,13 +20,17 @@ pub enum SchemaError {
|
|||||||
#[derive(Debug, TeError)]
|
#[derive(Debug, TeError)]
|
||||||
pub enum ParseProgramError {
|
pub enum ParseProgramError {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
BadFileName(#[from] win32::concept::BadFileNameError),
|
BadFileName(#[from] concept::BadFileNameError),
|
||||||
|
#[error("{0}")]
|
||||||
|
ParseCmdLine(#[from] concept::ParseCmdLineError),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
CastOsStr(#[from] utilities::CastOsStrError),
|
CastOsStr(#[from] utilities::CastOsStrError),
|
||||||
#[error("given path doesn't has legal file name part")]
|
#[error("given path doesn't has legal file name part")]
|
||||||
NoFileNamePart,
|
NoFileNamePart,
|
||||||
#[error("given path doesn't has legal directory part")]
|
#[error("given path doesn't has legal directory part")]
|
||||||
NoDirNamePart,
|
NoDirNamePart,
|
||||||
|
#[error("given identifier is not presented in dict")]
|
||||||
|
NoSuchIdentifier,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error occurs when operating with `Program`.
|
/// Error occurs when operating with `Program`.
|
||||||
@@ -177,9 +181,9 @@ pub struct Program {
|
|||||||
applications_key: lowlevel::ApplicationsKey,
|
applications_key: lowlevel::ApplicationsKey,
|
||||||
file_name: String,
|
file_name: String,
|
||||||
dir_name: String,
|
dir_name: String,
|
||||||
name: Rc<ProgramStr>,
|
name: Option<Rc<ProgramStr>>,
|
||||||
icon: Rc<ProgramIcon>,
|
icon: Option<Rc<ProgramIcon>>,
|
||||||
behavior: Rc<ProgramBehavior>,
|
behavior: Option<Rc<ProgramBehavior>>,
|
||||||
|
|
||||||
strs: Vec<Rc<ProgramStr>>,
|
strs: Vec<Rc<ProgramStr>>,
|
||||||
icons: Vec<Rc<ProgramIcon>>,
|
icons: Vec<Rc<ProgramIcon>>,
|
||||||
@@ -215,6 +219,36 @@ impl Program {
|
|||||||
.ok_or(ParseProgramError::NoDirNamePart)
|
.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.
|
/// Try creating Program from Schema.
|
||||||
pub fn new(schema: Schema) -> Result<Self, ParseProgramError> {
|
pub fn new(schema: Schema) -> Result<Self, ParseProgramError> {
|
||||||
// Extract file name part and directory name part respectively.
|
// 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 = Self::extract_dir_name(schema_path)?;
|
||||||
let dir_name = String::from(utilities::osstr_to_str(dir_name)?);
|
let dir_name = String::from(utilities::osstr_to_str(dir_name)?);
|
||||||
// Build app paths key and applications key respectively
|
// 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 app_paths_key = lowlevel::AppPathsKey::new(key.clone());
|
||||||
let applications_key = lowlevel::ApplicationsKey::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!();
|
todo!();
|
||||||
// Ok(Self {
|
// Ok(Self {
|
||||||
// app_paths_key,
|
// app_paths_key,
|
||||||
@@ -296,7 +372,7 @@ struct ProgramIcon {
|
|||||||
/// Internal used enum presenting a Program behavior (command line setups).
|
/// Internal used enum presenting a Program behavior (command line setups).
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ProgramBehavior {
|
struct ProgramBehavior {
|
||||||
inner: win32::concept::CmdLine,
|
inner: lowlevel::ShellVerb,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal used struct presenting a Program ProgId.
|
/// Internal used struct presenting a Program ProgId.
|
||||||
@@ -312,7 +388,7 @@ struct ProgramProgIdKey {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ProgramExtKey {
|
struct ProgramExtKey {
|
||||||
key: lowlevel::ExtKey,
|
key: lowlevel::ExtKey,
|
||||||
assoc: Rc<ProgramProgIdKey>
|
assoc: Rc<ProgramProgIdKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user