write shit
This commit is contained in:
@@ -8,3 +8,6 @@ license = "SPDX:MIT"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
winreg = "0.55.0"
|
||||
regex = "1.11.3"
|
||||
uuid = "1.18.1"
|
||||
|
||||
@@ -1,4 +1,67 @@
|
||||
/// The struct representing an Windows acceptable Prgram ID,
|
||||
use regex::Regex;
|
||||
use std::fmt::Display;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::sync::LazyLock;
|
||||
use thiserror::Error as TeError;
|
||||
|
||||
/// The register kind when registering program.
|
||||
pub enum RegisterKind {
|
||||
/// Register for current user.
|
||||
User,
|
||||
/// Register for all users under this computer.
|
||||
System,
|
||||
}
|
||||
|
||||
// region: File Extension
|
||||
|
||||
/// The struct representing an file extension which must start with dot (`.`)
|
||||
/// and followed by at least one arbitrary characters.
|
||||
pub struct FileExt {
|
||||
/// The body of file extension (excluding dot).
|
||||
inner: String,
|
||||
}
|
||||
|
||||
impl FileExt {
|
||||
pub fn new(file_ext: &str) -> Result<Self, ParseFileExtError> {
|
||||
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^\.([^\.]+)$").unwrap());
|
||||
match RE.captures(file_ext) {
|
||||
Some(v) => Ok(Self {
|
||||
inner: v[1].to_string(),
|
||||
}),
|
||||
None => Err(ParseFileExtError::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error occurs when try parsing string into FileExt.
|
||||
#[derive(Debug, TeError)]
|
||||
#[error("given file extension name is illegal")]
|
||||
pub struct ParseFileExtError {}
|
||||
|
||||
impl ParseFileExtError {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FileExt {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, ".{}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for FileExt {
|
||||
type Err = ParseFileExtError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
/// The struct representing an Windows acceptable Prgram ID,
|
||||
/// which looks like `Program.Document.2`
|
||||
pub struct ProgId {
|
||||
inner: String,
|
||||
@@ -12,30 +75,55 @@ impl ProgId {
|
||||
}
|
||||
}
|
||||
|
||||
/// Representing an file extension which must start with dot (`.`)
|
||||
/// and followed by arbitrary characters.
|
||||
pub struct FileExt {
|
||||
inner: String,
|
||||
// region: Executable Resource
|
||||
|
||||
/// The struct representing an Windows executable resources path like
|
||||
/// `path_to_file.exe,1`.
|
||||
pub struct ExecRc {
|
||||
/// The path to binary for finding resources.
|
||||
binary: PathBuf,
|
||||
/// The inner index of resources.
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl FileExt {
|
||||
pub fn new(file_ext: &str) -> Self {
|
||||
Self {
|
||||
inner: file_ext.to_string(),
|
||||
impl ExecRc {
|
||||
pub fn new(res_str: &str) -> Result<Self, ParseExecRcError> {
|
||||
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^([^,]+),([0-9]+)$").unwrap());
|
||||
let caps = RE.captures(res_str);
|
||||
if let Some(caps) = caps {
|
||||
let binary = PathBuf::from_str(&caps[1])?;
|
||||
let index = caps[2].parse::<u32>()?;
|
||||
Ok(Self { binary, index })
|
||||
} else {
|
||||
Err(ParseExecRcError::NoCapture)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representing an Windows recognizable icon string with format like:
|
||||
/// `@path_to_file.exe,61`.
|
||||
pub struct WinRc {
|
||||
inner: String,
|
||||
/// The error occurs when try parsing string into ExecRc.
|
||||
#[derive(Debug, TeError)]
|
||||
#[error("given string is not a valid executable resource string")]
|
||||
pub enum ParseExecRcError {
|
||||
/// Given string is not matched with format.
|
||||
NoCapture,
|
||||
/// Fail to convert executable part into path.
|
||||
BadBinaryPath(#[from] std::convert::Infallible),
|
||||
/// Fail to convert index part into valid number.
|
||||
BadIndex(#[from] std::num::ParseIntError),
|
||||
}
|
||||
|
||||
impl WinRc {
|
||||
pub fn new(icon: &str) -> Self {
|
||||
Self {
|
||||
inner: icon.to_string(),
|
||||
}
|
||||
impl FromStr for ExecRc {
|
||||
type Err = ParseExecRcError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
ExecRc::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ExecRc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{},{}", self.binary.to_str().unwrap(), self.index)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
15
wfassoc/src/error.rs
Normal file
15
wfassoc/src/error.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use thiserror::Error as TeError;
|
||||
|
||||
/// All possible error occurs in this crate.
|
||||
#[derive(Debug, TeError)]
|
||||
pub enum Error {
|
||||
#[error("can not register because lack essential privilege. please consider running with Administrator role")]
|
||||
NoPrivilege,
|
||||
#[error("{0}")]
|
||||
BadFileExt(#[from] super::components::ParseFileExtError),
|
||||
#[error("{0}")]
|
||||
BadExecRc(#[from] super::components::ParseExecRcError),
|
||||
}
|
||||
|
||||
/// The result type used in this crate.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -1,20 +1,13 @@
|
||||
//! This crate provide utilities fetching and manilupating Windows file association.
|
||||
//! All code under crate are following Microsoft document: https://learn.microsoft.com/en-us/windows/win32/shell/customizing-file-types-bumper
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
compile_error!("Crate wfassoc is only supported on Windows.");
|
||||
|
||||
pub(crate) mod error;
|
||||
pub(crate) mod components;
|
||||
pub(crate) mod program;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
||||
pub use error::Error as WfError;
|
||||
pub use program::Program;
|
||||
pub use components::RegisterKind;
|
||||
|
||||
@@ -1,17 +1,35 @@
|
||||
use super::error::{Error, Result};
|
||||
use super::components::*;
|
||||
|
||||
/// The struct representing a complete Win32 program.
|
||||
pub struct Program {
|
||||
name: String,
|
||||
prog_id: ProgId,
|
||||
file_exts: Vec<FileExt>,
|
||||
}
|
||||
|
||||
impl Program {
|
||||
/// Create a program descriptor.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: String::new(),
|
||||
prog_id: ProgId::new(""),
|
||||
file_exts: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Program {
|
||||
/// Register program in this computer
|
||||
pub fn register(&self, kind: RegisterKind) -> Result<()> {
|
||||
todo!("pretend to register >_<...")
|
||||
}
|
||||
|
||||
/// Unregister program from this computer.
|
||||
pub fn unregister(&self) -> Result<()> {
|
||||
todo!("pretend to unregister >_<...")
|
||||
}
|
||||
}
|
||||
|
||||
impl Program {
|
||||
/// Query file extension infos which this program want to associate with.
|
||||
pub fn query(&self) -> Result<()> {
|
||||
todo!("pretend to query >_<...")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user