use std::{
ffi::{c_char, c_void, CStr, CString},
fs, io,
path::Path,
ptr::{self, NonNull},
sync::LockResult,
};
#[cfg(feature = "dialog")]
use crate::dialog::*;
use crate::{http::status::StatusCode, CResult, Error, Result, WebResult};
use chrono::{DateTime, Datelike, Local, Timelike};
use lazy_static::lazy_static;
use regex::Regex;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::Value;
lazy_static! {
static ref REGEX_FORMAT_PATTERN: Regex = Regex::new(r"\{([a-zA-Z0-9_]+)\}").unwrap();
}
#[cfg(target_os = "windows")]
lazy_static! {
static ref REGEX_ENV_PATTERN: Regex = Regex::new(r"\%([a-zA-Z0-9_]+)\%").unwrap();
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
lazy_static! {
static ref REGEX_ENV_PATTERN: Regex = Regex::new(r"\$\{([a-zA-Z0-9_]+)\}").unwrap();
}
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os = "macos")))]
lazy_static! {
static ref REGEX_ENV_PATTERN: Regex = Regex::new(r"\$([a-zA-Z0-9_]+)").unwrap();
}
pub trait ToStringWithoutNulls {
fn to_string_without_nulls(&self) -> String;
}
impl ToStringWithoutNulls for [u8] {
fn to_string_without_nulls(&self) -> String {
let mut result = String::with_capacity(self.len());
for &byte in self {
if byte != 0 {
result.push(byte as char);
}
}
result
}
}
impl ToStringWithoutNulls for Vec<u8> {
fn to_string_without_nulls(&self) -> String {
let mut result = String::with_capacity(self.len());
for &byte in self {
if byte != 0 {
result.push(byte as char);
}
}
result
}
}
pub fn any_to_c_ptr2<T>(value: &T) -> *const c_void {
value as *const T as *const c_void
}
pub unsafe fn c_ptr_to_any2<T>(pointer: *const c_void) -> T {
ptr::read(pointer as *const T)
}
pub fn any_to_c_ptr<T>(boxed_value: Box<T>) -> *const c_void {
Box::into_raw(boxed_value) as *const T as *const c_void
}
pub unsafe fn c_ptr_to_any<T>(void_ptr: *const c_void) -> Option<Box<T>> {
let non_null_ptr = NonNull::new(void_ptr as *mut T);
non_null_ptr.map(|ptr| Box::from_raw(ptr.as_ptr() as *mut T))
}
pub fn any_to_c_mut_ptr<T: Sized>(boxed_value: Box<T>) -> *mut c_void {
Box::into_raw(boxed_value) as *mut T as *mut c_void
}
pub unsafe fn c_mut_ptr_to_any<T: Sized>(void_ptr: *mut c_void) -> Option<Box<T>> {
let non_null_ptr = NonNull::new(void_ptr as *mut T);
non_null_ptr.map(|ptr| Box::from_raw(ptr.as_ptr() as *mut T))
}
pub trait AutoParse {
fn to_cstring(&self) -> Result<CString>;
fn to_c_char(&self) -> *const std::ffi::c_char;
}
impl<S: Serialize + AsRef<str>> AutoParse for S {
fn to_cstring(&self) -> Result<CString> {
Ok(CString::new(self.as_ref())?)
}
fn to_c_char(&self) -> *const std::ffi::c_char {
self.to_cstring().def().into_raw()
}
}
impl AutoParse for Path {
fn to_cstring(&self) -> Result<CString> {
Ok(CString::new(
self
.to_str()
.ok_or(Error::Str("AutoParse<to_cstring<解析>>".into()))?,
)?)
}
fn to_c_char(&self) -> *const std::ffi::c_char {
self.to_cstring().def().into_raw()
}
}
pub unsafe trait CAutoParse {
unsafe fn c_to_cstring(&self) -> CString;
unsafe fn c_to_string(&self) -> String;
fn c_to_ptr(self) -> *const c_void;
fn c_to_mut_ptr(self) -> *mut c_void;
unsafe fn c_to_any<T>(self) -> Option<Box<T>>;
}
unsafe impl CAutoParse for *const c_char {
unsafe fn c_to_cstring(&self) -> CString {
unsafe { CStr::from_ptr(*self).into() }
}
unsafe fn c_to_string(&self) -> String {
self.c_to_cstring().into_string().def()
}
unsafe fn c_to_any<T: Sized>(self) -> Option<Box<T>> {
c_ptr_to_any(self.c_to_ptr())
}
fn c_to_ptr(self) -> *const c_void {
any_to_c_ptr(Box::new(self))
}
fn c_to_mut_ptr(self) -> *mut c_void {
any_to_c_mut_ptr(Box::new(self))
}
}
unsafe impl CAutoParse for *mut c_char {
unsafe fn c_to_cstring(&self) -> CString {
CString::from_raw(*self)
}
unsafe fn c_to_string(&self) -> String {
self.c_to_cstring().into_string().def()
}
fn c_to_ptr(self) -> *const c_void {
any_to_c_ptr(Box::new(self))
}
fn c_to_mut_ptr(self) -> *mut c_void {
any_to_c_mut_ptr(Box::new(self))
}
unsafe fn c_to_any<T: Sized>(self) -> Option<Box<T>> {
c_ptr_to_any(self.c_to_ptr())
}
}
unsafe impl CAutoParse for *const c_void {
unsafe fn c_to_cstring(&self) -> CString {
panic!("不支持c_void")
}
unsafe fn c_to_string(&self) -> String {
panic!("不支持c_void")
}
fn c_to_ptr(self) -> *const c_void {
self
}
fn c_to_mut_ptr(self) -> *mut c_void {
self as *mut c_void
}
unsafe fn c_to_any<T>(self) -> Option<Box<T>> {
c_ptr_to_any(self)
}
}
unsafe impl CAutoParse for *mut c_void {
unsafe fn c_to_cstring(&self) -> CString {
panic!("不支持c_void")
}
unsafe fn c_to_string(&self) -> String {
panic!("不支持c_void")
}
fn c_to_ptr(self) -> *const c_void {
self as *const c_void
}
fn c_to_mut_ptr(self) -> *mut c_void {
self
}
unsafe fn c_to_any<T>(self) -> Option<Box<T>> {
c_ptr_to_any(self.c_to_mut_ptr())
}
}
pub trait ParseResult<T> {
fn res(self) -> Result<T>;
fn res_c(self) -> CResult<T>;
fn un(self, _title: &str, add: &str) -> T;
}
pub trait ParseWebResult<T: Serialize> {
fn res_web(&self) -> Result<WebResult<String>>;
}
impl<T: Serialize> ParseWebResult<T> for Result<T> {
fn res_web(&self) -> Result<WebResult<String>> {
Result::Ok(match self {
Result::Ok(data) => WebResult {
code: StatusCode::OK.into(),
msg: "OK".into(),
data: serde_json::to_string(&data)?,
},
Result::Err(e) => WebResult {
code: e.status_code().into(),
msg: e.to_string().into(),
data: String::new(),
},
})
}
}
pub trait ParseResultDefault<T> {
fn def(self) -> T;
}
impl<T: Default> ParseResultDefault<T> for LockResult<T> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for Result<T> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for CResult<T> {
fn def(self) -> T {
self.res().unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for std::result::Result<T, std::io::Error> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for std::result::Result<T, std::ffi::IntoStringError> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for std::result::Result<T, std::env::VarError> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T: Default> ParseResultDefault<T> for Option<T> {
fn def(self) -> T {
self.unwrap_or_default()
}
}
impl<T> ParseResult<T> for LockResult<T> {
fn res(self) -> Result<T> {
match self {
Self::Ok(x) => Ok(x),
Self::Err(e) => Err(Error::unprocessable_entity([(
"LockResult<T,PoisonError<T>>",
e.to_string(),
)])),
}
}
fn res_c(self) -> CResult<T> {
self.res().into()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for Result<T> {
fn res(self) -> Result<T> {
self
}
fn res_c(self) -> CResult<T> {
self.into()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for CResult<T> {
fn res(self) -> Result<T> {
self.into()
}
fn res_c(self) -> CResult<T> {
self
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for Option<T> {
fn res(self) -> Result<T> {
self.ok_or(Error::Option("ParseResult".into()))
}
fn res_c(self) -> CResult<T> {
self.res().res_c()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Some(x) => x,
Self::None => {
let ref msg = format!("{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for std::result::Result<T, Box<dyn std::any::Any + Send + Sync>> {
fn res(self) -> Result<T> {
match self {
Self::Ok(r) => Result::Ok(r),
Self::Err(e) => Result::Err(Error::any(e)),
}
}
fn res_c(self) -> CResult<T> {
self.res().res_c()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e:?};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for std::result::Result<T, std::io::Error> {
fn res(self) -> Result<T> {
match self {
Self::Ok(r) => Result::Ok(r),
Self::Err(e) => Result::Err(Error::Io(e)),
}
}
fn res_c(self) -> CResult<T> {
self.res().res_c()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block("Std Result io 错误", msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for std::result::Result<T, std::ffi::IntoStringError> {
fn res(self) -> Result<T> {
match self {
Self::Ok(r) => Result::Ok(r),
Self::Err(e) => Result::Err(Error::any(Box::new(e))),
}
}
fn res_c(self) -> CResult<T> {
self.res().res_c()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
impl<T> ParseResult<T> for std::result::Result<T, std::env::VarError> {
fn res(self) -> Result<T> {
match self {
Self::Ok(r) => Result::Ok(r),
Self::Err(e) => Result::Err(Error::any(Box::new(e))),
}
}
fn res_c(self) -> CResult<T> {
self.res().res_c()
}
fn un(self, _title: &str, add: &str) -> T {
match self {
Self::Ok(x) => x,
Self::Err(e) => {
let ref msg = format!("{e};{add}");
#[cfg(feature = "dialog")]
dialog_err_block(_title, msg);
panic!("{}", msg)
}
}
}
}
pub trait MyParseFormat {
fn parse_all(&self) -> Result<String>;
fn parse_format(&self) -> Result<String>;
fn parse_replace<F>(&self, start: char, end: char, match_value: F) -> Result<String>
where
F: Fn(String) -> String;
fn parse_env(&self) -> Result<String>;
fn parse_path(&self) -> String;
fn to_value(&self) -> Result<Value>;
}
impl<S: AsRef<str>> MyParseFormat for S {
fn parse_all(&self) -> Result<String> {
self.as_ref().parse_format()?.parse_path().parse_env()
}
fn parse_format(&self) -> Result<String> {
let local: DateTime<Local> = Local::now();
Ok(
REGEX_FORMAT_PATTERN
.replace_all(self.as_ref(), |caps: ®ex::Captures<'_>| {
let key: String = caps.get(1).map_or("", |m| m.as_str()).to_lowercase();
match &*key {
"date" => format!(
"{:04}-{:02}-{:02}",
local.year(),
local.month(),
local.day()
),
"time" => format!(
"{:02}:{:02}:{:02}",
local.hour(),
local.minute(),
local.second()
),
"timestamp-millis" => local.timestamp_millis().to_string(),
"day" => format!("{:02}", local.day()),
"month" => format!("{:02}", local.month()),
"year" => format!("{:02}", local.year()),
"hour" => format!("{:02}", local.hour()),
"minute" => format!("{:02}", local.minute()),
"second" => format!("{:02}", local.second()),
"cwd" => std::env::current_dir()
.and_then(|x| Ok(x.display().to_string()))
.def(),
"nanoid" => {
#[cfg(feature = "algorithm")]
return crate::algorithm!(nanoid 12);
#[cfg(not(feature = "algorithm"))]
return String::new();
}
_ => String::new(),
}
})
.to_string(),
)
}
fn parse_env(&self) -> Result<String> {
Ok(
REGEX_ENV_PATTERN
.replace_all(self.as_ref(), |caps: ®ex::Captures<'_>| {
let key = caps.get(1).map_or("", |m| m.as_str());
let var = std::env::var(key).def();
var
})
.to_string(),
)
}
fn to_value(&self) -> Result<Value> {
Ok(serde_json::from_str::<Value>(self.as_ref())?)
}
fn parse_path(&self) -> String {
self.as_ref().replace("\\\\", "/").replace("\\", "/")
}
fn parse_replace<F>(&self, start: char, end: char, match_callback: F) -> Result<String>
where
F: Fn(String) -> String,
{
let re = Regex::new(&format!(r"\{}([a-zA-Z0-9_]+)\{}", start, end))?;
Ok(
re.replace_all(self.as_ref(), |caps: ®ex::Captures<'_>| {
let key: String = caps.get(1).map_or("", |m| m.as_str()).to_lowercase();
match_callback(key)
})
.to_string(),
)
}
}
impl MyParseFormat for Path {
fn parse_format(&self) -> Result<String> {
self.to_string_lossy().parse_format()
}
fn parse_env(&self) -> Result<String> {
self.to_string_lossy().parse_env()
}
fn to_value(&self) -> Result<Value> {
self.to_string_lossy().to_value()
}
fn parse_all(&self) -> Result<String> {
self.to_string_lossy().parse_all()
}
fn parse_path(&self) -> String {
self.to_string_lossy().parse_path()
}
fn parse_replace<F>(&self, start: char, end: char, match_value: F) -> Result<String>
where
F: Fn(String) -> String,
{
self
.to_string_lossy()
.parse_replace(start, end, match_value)
}
}
pub trait AutoJson {
fn auto_write_json<T: Serialize>(&self, content: T) -> std::io::Result<()>;
fn auto_read_json<R: DeserializeOwned>(&self) -> std::io::Result<R>;
}
impl<S: Serialize + AsRef<Path>> AutoJson for S {
fn auto_write_json<T: Serialize>(&self, content: T) -> std::io::Result<()> {
let mut parent = self.as_ref().to_path_buf();
parent.pop();
if !parent.exists() {
fs::create_dir_all(parent)?;
}
fs::write(self, serde_json::to_string_pretty(&content)?)?;
std::io::Result::Ok(())
}
fn auto_read_json<R: DeserializeOwned>(&self) -> std::io::Result<R> {
std::io::Result::Ok(serde_json::from_str::<R>(&std::fs::read_to_string(
self.as_ref(),
)?)?)
}
}
pub trait AutoPath {
fn auto_create_dir(&self) -> Result<()>;
fn auto_remove_dir(&self) -> Result<()>;
fn auto_create_file<S>(&self, content: S) -> Result<()>
where
S: AsRef<str>;
fn auto_remove_file(&self) -> Result<()>;
}
impl<T: AsRef<str>> AutoPath for T {
fn auto_create_dir(&self) -> Result<()> {
Path::new(self.as_ref()).auto_create_dir()
}
fn auto_remove_dir(&self) -> Result<()> {
Path::new(self.as_ref()).auto_remove_dir()
}
fn auto_create_file<S>(&self, content: S) -> Result<()>
where
S: AsRef<str>,
{
Path::new(self.as_ref()).auto_create_file(content)
}
fn auto_remove_file(&self) -> Result<()> {
Path::new(self.as_ref()).auto_remove_file()
}
}
impl AutoPath for Path {
fn auto_create_dir(&self) -> Result<()> {
let x = if self.extension().is_some() {
self.parent().ok_or(Error::String(format!(
"{} -> {}",
self.to_string_lossy(),
io::ErrorKind::InvalidData.to_string()
)))?
} else {
self
};
if !x.exists() {
fs::create_dir_all(x)?;
}
Ok(())
}
fn auto_remove_dir(&self) -> Result<()> {
if self.is_dir() {
if self.exists() {
fs::remove_dir_all(self)?;
if self.exists() {
return Err(Error::Str(
format!(
"{} -> {}",
self.to_string_lossy(),
io::ErrorKind::AlreadyExists.to_string()
)
.into(),
));
}
}
} else {
return Err(Error::Str(
format!(
"{} -> {}",
self.to_string_lossy(),
io::ErrorKind::Unsupported.to_string()
)
.into(),
));
}
Ok(())
}
fn auto_create_file<S>(&self, data: S) -> Result<()>
where
S: AsRef<str>,
{
if !self.exists() {
fs::write(self, data.as_ref())?;
} else if !self.is_file() {
return Err(Error::Str(
format!(
"{} -> {}",
self.to_string_lossy(),
io::ErrorKind::AlreadyExists.to_string()
)
.into(),
));
}
Ok(())
}
fn auto_remove_file(&self) -> Result<()> {
if self.exists() && self.is_file() {
fs::remove_file(self)?;
} else if !self.is_file() {
return Err(Error::Str(
format!(
"{} -> {}",
self.to_string_lossy(),
io::ErrorKind::AlreadyExists.to_string()
)
.into(),
));
}
Ok(())
}
}
pub mod raw_pointer_serializer {
use serde::{Deserialize, Deserializer, Serializer};
use super::{any_to_c_mut_ptr, c_mut_ptr_to_any};
pub fn serialize<S>(raw_ptr: &*mut std::ffi::c_void, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let raw_ptr_address =
unsafe { c_mut_ptr_to_any::<u64>(*raw_ptr) }.expect("raw_pointer_serializer serialize");
serializer.serialize_u64(*raw_ptr_address)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<*mut std::ffi::c_void, D::Error>
where
D: Deserializer<'de>,
{
let raw_ptr_address: u64 = Deserialize::deserialize(deserializer)?;
let raw_ptr = any_to_c_mut_ptr(Box::new(raw_ptr_address));
Ok(raw_ptr)
}
}
pub mod c_str_pointer_serializer {
use super::{AutoParse as _, CAutoParse as _};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(
raw_ptr: &*const std::ffi::c_char,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&*unsafe { raw_ptr.c_to_string() })
}
pub fn deserialize<'de, D>(
deserializer: D,
) -> std::result::Result<*const std::ffi::c_char, D::Error>
where
D: Deserializer<'de>,
{
let raw_ptr_address: &str = Deserialize::deserialize(deserializer)?;
Ok(raw_ptr_address.to_c_char())
}
}
#[cfg(feature = "ui")]
#[cfg(target_os = "windows")]
pub mod hwnd_serializer {
use crate::ui::HWND;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(raw_ptr: &HWND, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let raw_ptr_address = *raw_ptr as *mut std::ffi::c_void as usize;
serializer.serialize_u64(raw_ptr_address as u64)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<HWND, D::Error>
where
D: Deserializer<'de>,
{
let raw_ptr_address: u64 = Deserialize::deserialize(deserializer)?;
let raw_ptr = raw_ptr_address as *mut std::ffi::c_void as HWND;
Ok(raw_ptr)
}
}