write shit

This commit is contained in:
2025-10-05 18:04:20 +08:00
parent f3c7f0905e
commit 03a1796e07
8 changed files with 693 additions and 38 deletions

View File

@@ -8,3 +8,6 @@ license = "SPDX:MIT"
[dependencies]
thiserror = { workspace = true }
winreg = "0.55.0"
regex = "1.11.3"
uuid = "1.18.1"

View File

@@ -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
View 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>;

View File

@@ -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;

View File

@@ -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 >_<...")
}
}