mirror of
https://github.com/sxyazi/yazi.git
synced 2026-05-13 08:16:40 +00:00
feat: make Action a deserializer (#3841)
This commit is contained in:
parent
6b143c1f4d
commit
4857d46918
44 changed files with 1281 additions and 381 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
|
@ -433,7 +433,7 @@ version = "0.12.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
|
||||
dependencies = [
|
||||
"hybrid-array 0.4.9",
|
||||
"hybrid-array 0.4.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -922,7 +922,7 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
|
||||
dependencies = [
|
||||
"hybrid-array 0.4.9",
|
||||
"hybrid-array 0.4.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1851,9 +1851,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a79f2aff40c18ab8615ddc5caa9eb5b96314aef18fe5823090f204ad988e813"
|
||||
checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
|
@ -2083,9 +2083,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.93"
|
||||
version = "0.3.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "797146bb2677299a1eb6b7b50a890f4c361b29ef967addf5b2fa45dae1bb6d7d"
|
||||
checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
|
|
@ -2172,9 +2172,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.183"
|
||||
version = "0.2.184"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
|
|
@ -3377,7 +3377,7 @@ dependencies = [
|
|||
"kasuari",
|
||||
"lru",
|
||||
"serde",
|
||||
"strum",
|
||||
"strum 0.27.2",
|
||||
"thiserror 2.0.18",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate",
|
||||
|
|
@ -3442,7 +3442,7 @@ dependencies = [
|
|||
"line-clipping",
|
||||
"ratatui-core",
|
||||
"serde",
|
||||
"strum",
|
||||
"strum 0.27.2",
|
||||
"time",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
|
|
@ -3921,9 +3921,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98"
|
||||
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
|
@ -4239,7 +4239,16 @@ version = "0.27.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
"strum_macros 0.27.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
|
||||
dependencies = [
|
||||
"strum_macros 0.28.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4254,6 +4263,18 @@ dependencies = [
|
|||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
|
|
@ -4553,9 +4574,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc"
|
||||
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
|
||||
dependencies = [
|
||||
"indexmap 2.13.0",
|
||||
"serde_core",
|
||||
|
|
@ -4568,27 +4589,27 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f"
|
||||
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
|
||||
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.1.0+spec-1.1.0"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed"
|
||||
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
|
|
@ -4907,9 +4928,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.116"
|
||||
version = "0.2.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dc0882f7b5bb01ae8c5215a1230832694481c1a4be062fd410e12ea3da5b631"
|
||||
checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -4920,9 +4941,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.66"
|
||||
version = "0.4.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19280959e2844181895ef62f065c63e0ca07ece4771b53d89bfdb967d97cbf05"
|
||||
checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -4930,9 +4951,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.116"
|
||||
version = "0.2.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75973d3066e01d035dbedaad2864c398df42f8dd7b1ea057c35b8407c015b537"
|
||||
checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -4940,9 +4961,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.116"
|
||||
version = "0.2.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91af5e4be765819e0bcfee7322c14374dc821e35e72fa663a830bbc7dc199eac"
|
||||
checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
|
|
@ -4953,9 +4974,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.116"
|
||||
version = "0.2.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9bf0406a78f02f336bf1e451799cca198e8acde4ffa278f0fb20487b150a633"
|
||||
checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -6067,8 +6088,10 @@ dependencies = [
|
|||
"memchr",
|
||||
"ordered-float 5.3.0",
|
||||
"parking_lot",
|
||||
"paste",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"strum 0.28.0",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"typed-path",
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ futures = "0.3.32"
|
|||
globset = "0.4.18"
|
||||
hashbrown = { version = "0.16.1", features = [ "serde" ] }
|
||||
indexmap = { version = "2.13.0", features = [ "serde" ] }
|
||||
libc = "0.2.183"
|
||||
libc = "0.2.184"
|
||||
lru = "0.16.3"
|
||||
mlua = { version = "0.11.6", features = [ "anyhow", "async", "error-send", "lua55", "macros", "serde" ] }
|
||||
objc2 = "0.6.4"
|
||||
|
|
@ -67,12 +67,13 @@ scopeguard = "1.2.0"
|
|||
serde = { version = "1.0.228", features = [ "derive" ] }
|
||||
serde_json = "1.0.149"
|
||||
serde_with = "3.18.0"
|
||||
strum = { version = "0.28.0", features = [ "derive" ] }
|
||||
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||
thiserror = "2.0.18"
|
||||
tokio = { version = "1.50.0", features = [ "full" ] }
|
||||
tokio-stream = "0.1.18"
|
||||
tokio-util = "0.7.18"
|
||||
toml = { version = "1.1.0" }
|
||||
toml = { version = "1.1.2" }
|
||||
tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_debug" ] }
|
||||
twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
|
||||
typed-path = "0.12.3"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ impl Actor for UpdateMimes {
|
|||
let updates = opt
|
||||
.updates
|
||||
.into_iter()
|
||||
.flat_map(|(key, value)| key.into_url().zip(value.into_sstr()))
|
||||
.filter(|(url, mime)| cx.mgr.mimetype.get(url) != Some(mime))
|
||||
.fold(HashMap::new(), |mut map, (u, m)| {
|
||||
for u in linked.from_file(u.as_url()) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl Scheme {
|
|||
|
||||
impl UserData for Scheme {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
cached_field!(fields, kind, |_, me| Ok(me.kind().as_str()));
|
||||
cached_field!(fields, kind, |_, me| Ok(Into::<&'static str>::into(me.kind())));
|
||||
cached_field!(fields, cache, |_, me| Ok(me.cache().map(Path::new)));
|
||||
|
||||
fields.add_field_method_get("is_virtual", |_, me| Ok(me.is_virtual()));
|
||||
|
|
|
|||
|
|
@ -5,22 +5,18 @@ use yazi_shared::{event::ActionCow, strand::StrandBuf};
|
|||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct QuitOpt {
|
||||
#[serde(default)]
|
||||
pub code: i32,
|
||||
#[serde(skip)]
|
||||
pub selected: Option<StrandBuf>,
|
||||
#[serde(default, alias = "no-cwd-file")]
|
||||
pub no_cwd_file: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for QuitOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
code: a.get("code").unwrap_or_default(),
|
||||
selected: None,
|
||||
no_cwd_file: a.bool("no-cwd-file"),
|
||||
})
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for QuitOpt {
|
||||
|
|
|
|||
|
|
@ -4,15 +4,17 @@ use mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{DurationSecondsWithFrac, serde_as};
|
||||
use yazi_binding::SER_OPT;
|
||||
use yazi_shared::{data::Data, event::ActionCow};
|
||||
use yazi_shared::event::ActionCow;
|
||||
|
||||
use crate::notify::MessageLevel;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct MessageOpt {
|
||||
pub title: String,
|
||||
#[serde(alias = "0")]
|
||||
pub content: String,
|
||||
#[serde(alias = "1")]
|
||||
pub title: String,
|
||||
#[serde(default)]
|
||||
pub level: MessageLevel,
|
||||
#[serde_as(as = "DurationSecondsWithFrac<f64>")]
|
||||
|
|
@ -22,14 +24,7 @@ pub struct MessageOpt {
|
|||
impl TryFrom<ActionCow> for MessageOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
title: a.take_second()?,
|
||||
content: a.take_first()?,
|
||||
level: <_>::deserialize(a.get::<&Data>("level")?)?,
|
||||
timeout: <_>::deserialize(a.get::<&Data>("timeout")?)?,
|
||||
})
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for MessageOpt {
|
||||
|
|
|
|||
|
|
@ -78,9 +78,8 @@ impl<'a> FsUrl<'a> for UrlCow<'a> {
|
|||
|
||||
fn unified_path(self) -> Cow<'a, Path> {
|
||||
match self {
|
||||
Self::Regular(loc) | Self::Search { loc, .. } => loc.into_inner().into(),
|
||||
Self::RegularRef(loc) | Self::SearchRef { loc, .. } => loc.as_inner().into(),
|
||||
Self::Archive { .. } | Self::ArchiveRef { .. } | Self::Sftp { .. } | Self::SftpRef { .. } => {
|
||||
Self::Regular(loc) | Self::Search { loc, .. } => loc.into_inner(),
|
||||
Self::Archive { .. } | Self::Sftp { .. } => {
|
||||
self.cache().expect("non-local URL should have a cache path").into()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeprecateForm {
|
||||
pub content: SStr,
|
||||
}
|
||||
|
|
@ -10,13 +10,7 @@ pub struct DeprecateForm {
|
|||
impl TryFrom<ActionCow> for DeprecateForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let Ok(content) = a.take("content") else {
|
||||
bail!("Invalid 'content' in DeprecateForm");
|
||||
};
|
||||
|
||||
Ok(Self { content })
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for DeprecateForm {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@ use std::fmt::Debug;
|
|||
|
||||
use anyhow::Result;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
pub struct LuaForm {
|
||||
#[serde(alias = "0")]
|
||||
pub code: SStr,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for LuaForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> { Ok(Self { code: a.take_first()? }) }
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for LuaForm {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{Layer, event::ActionCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ToggleForm {
|
||||
#[serde(alias = "0")]
|
||||
pub layer: Layer,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for ToggleForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(Self { layer: a.str(0).parse()? }) }
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl From<Layer> for ToggleForm {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{event::ActionCow, url::UrlCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct BulkExitForm {
|
||||
#[serde(alias = "0")]
|
||||
pub target: UrlCow<'static>,
|
||||
#[serde(default)]
|
||||
pub accept: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for BulkExitForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let Ok(target) = a.take_first::<UrlCow>() else {
|
||||
bail!("invalid target in BulkExitForm");
|
||||
};
|
||||
|
||||
Ok(Self { target, accept: a.bool("accept") })
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for BulkExitForm {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LinemodeForm {
|
||||
#[serde(alias = "0")]
|
||||
pub new: SStr,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for LinemodeForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let Ok(new) = a.take_first::<SStr>() else {
|
||||
bail!("a string argument is required for LinemodeForm");
|
||||
};
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let me: Self = a.deserialize()?;
|
||||
|
||||
if new.is_empty() || new.len() > 20 {
|
||||
if me.new.is_empty() || me.new.len() > 20 {
|
||||
bail!("Linemode must be between 1 and 20 characters long");
|
||||
}
|
||||
|
||||
Ok(Self { new })
|
||||
Ok(me)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow, url::UrlCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ShellForm {
|
||||
#[serde(default, alias = "0")]
|
||||
pub run: SStr,
|
||||
pub cwd: Option<UrlCow<'static>>,
|
||||
|
||||
#[serde(default)]
|
||||
pub block: bool,
|
||||
#[serde(default)]
|
||||
pub orphan: bool,
|
||||
#[serde(default)]
|
||||
pub interactive: bool,
|
||||
|
||||
pub cursor: Option<usize>,
|
||||
|
|
@ -17,17 +22,8 @@ pub struct ShellForm {
|
|||
impl TryFrom<ActionCow> for ShellForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let me = Self {
|
||||
run: a.take_first().unwrap_or_default(),
|
||||
cwd: a.take("cwd").ok(),
|
||||
|
||||
block: a.bool("block"),
|
||||
orphan: a.bool("orphan"),
|
||||
interactive: a.bool("interactive"),
|
||||
|
||||
cursor: a.get("cursor").ok(),
|
||||
};
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let me: Self = a.deserialize()?;
|
||||
|
||||
if me.cursor.is_some_and(|c| c > me.run.chars().count()) {
|
||||
bail!("The cursor position is out of bounds.");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ use yazi_shared::event::ActionCow;
|
|||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct SortForm {
|
||||
#[serde(alias = "0")]
|
||||
pub by: Option<SortBy>,
|
||||
pub reverse: Option<bool>,
|
||||
#[serde(alias = "dir-first")]
|
||||
pub dir_first: Option<bool>,
|
||||
pub sensitive: Option<bool>,
|
||||
pub translit: Option<bool>,
|
||||
|
|
@ -17,16 +19,7 @@ pub struct SortForm {
|
|||
impl TryFrom<ActionCow> for SortForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
by: a.first().ok().map(str::parse).transpose()?,
|
||||
reverse: a.get("reverse").ok(),
|
||||
dir_first: a.get("dir-first").ok(),
|
||||
sensitive: a.get("sensitive").ok(),
|
||||
translit: a.get("translit").ok(),
|
||||
fallback: a.get("fallback").ok().map(str::parse).transpose()?,
|
||||
})
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for SortForm {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,27 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct TabRenameForm {
|
||||
#[serde(alias = "0")]
|
||||
pub name: Option<SStr>,
|
||||
#[serde(default)]
|
||||
pub interactive: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for TabRenameForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let name = a.take_first().ok();
|
||||
let interactive = a.bool("interactive");
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let me: Self = a.deserialize()?;
|
||||
|
||||
if name.is_none() && !interactive {
|
||||
if me.name.is_none() && !me.interactive {
|
||||
bail!("either name or interactive must be specified in TabRenameForm");
|
||||
}
|
||||
|
||||
Ok(Self { name, interactive })
|
||||
Ok(me)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,23 +1,17 @@
|
|||
use anyhow::bail;
|
||||
use hashbrown::HashMap;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use yazi_shared::{data::{Data, DataKey}, event::ActionCow};
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{SStr, event::ActionCow, url::UrlCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateMimesForm {
|
||||
pub updates: HashMap<DataKey, Data>,
|
||||
pub updates: HashMap<UrlCow<'static>, SStr>,
|
||||
}
|
||||
|
||||
impl TryFrom<ActionCow> for UpdateMimesForm {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut a: ActionCow) -> Result<Self, Self::Error> {
|
||||
let Ok(updates) = a.take("updates") else {
|
||||
bail!("Invalid 'updates' in UpdateMimesForm");
|
||||
};
|
||||
|
||||
Ok(Self { updates })
|
||||
}
|
||||
fn try_from(a: ActionCow) -> Result<Self, Self::Error> { Ok(a.deserialize()?) }
|
||||
}
|
||||
|
||||
impl FromLua for UpdateMimesForm {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl HookInOutCopy {
|
|||
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
if let TaskProg::FileCopy(_) = &task.prog {
|
||||
task.hook = Some(HookIn::from(self).with_id(task.id));
|
||||
task.with_hook(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ impl HookInOutCut {
|
|||
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
if let TaskProg::FileCut(_) = &task.prog {
|
||||
task.hook = Some(HookIn::from(self).with_id(task.id));
|
||||
task.with_hook(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ impl HookInOutLink {
|
|||
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
if let TaskProg::FileLink(_) = &task.prog {
|
||||
task.hook = Some(HookIn::from(self).with_id(task.id));
|
||||
task.with_hook(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -174,7 +174,7 @@ impl HookInOutHardlink {
|
|||
|
||||
pub(crate) fn reduce(self, task: &mut Task) {
|
||||
if let TaskProg::FileHardlink(_) = &task.prog {
|
||||
task.hook = Some(HookIn::from(self).with_id(task.id));
|
||||
task.with_hook(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ impl<'de> serde::Deserializer<'de> for &mut Deserializer<'de> {
|
|||
let b = self.input.get(..len).ok_or(Error::serde("string not enough"))?;
|
||||
|
||||
self.input = &self.input[len..];
|
||||
visitor.visit_str(str::from_utf8(b).map_err(|e| Error::serde(e.to_string()))?)
|
||||
visitor.visit_borrowed_str(str::from_utf8(b).map_err(|e| Error::serde(e.to_string()))?)
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
|
|
@ -156,7 +156,7 @@ impl<'de> serde::Deserializer<'de> for &mut Deserializer<'de> {
|
|||
let b = self.input.get(4..4 + len).ok_or(Error::serde("bytes not enough"))?;
|
||||
|
||||
self.input = &self.input[4 + len..];
|
||||
visitor.visit_bytes(b)
|
||||
visitor.visit_borrowed_bytes(b)
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ hashbrown = { workspace = true }
|
|||
memchr = "2.8.0"
|
||||
ordered-float = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
typed-path = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -267,53 +267,5 @@ impl Data {
|
|||
}
|
||||
}
|
||||
|
||||
// --- Macros
|
||||
macro_rules! impl_into_integer {
|
||||
($t:ty) => {
|
||||
impl TryFrom<&Data> for $t {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &Data) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
Data::Integer(i) => <$t>::try_from(*i)?,
|
||||
Data::String(s) => s.parse()?,
|
||||
Data::Id(i) => <$t>::try_from(i.get())?,
|
||||
_ => bail!("not an integer"),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_into_number {
|
||||
($t:ty) => {
|
||||
impl TryFrom<&Data> for $t {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &Data) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
Data::Integer(i) if *i == (*i as $t as _) => *i as $t,
|
||||
Data::Number(n) if *n == (*n as $t as _) => *n as $t,
|
||||
Data::String(s) => s.parse()?,
|
||||
Data::Id(i) if i.get() == (i.get() as $t as _) => i.get() as $t,
|
||||
_ => bail!("not a number"),
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_into_integer!(i8);
|
||||
impl_into_integer!(i16);
|
||||
impl_into_integer!(i32);
|
||||
impl_into_integer!(i64);
|
||||
impl_into_integer!(isize);
|
||||
impl_into_integer!(u8);
|
||||
impl_into_integer!(u16);
|
||||
impl_into_integer!(u32);
|
||||
impl_into_integer!(u64);
|
||||
impl_into_integer!(usize);
|
||||
impl_into_integer!(crate::Id);
|
||||
|
||||
impl_into_number!(f32);
|
||||
impl_into_number!(f64);
|
||||
impl_into_integer!(Data, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, crate::Id);
|
||||
impl_into_number!(Data, f32, f64);
|
||||
|
|
|
|||
|
|
@ -1,110 +1,110 @@
|
|||
use serde::de::{Error, IntoDeserializer, MapAccess, SeqAccess};
|
||||
use serde::{Deserializer, de::{self, Error, IntoDeserializer, MapAccess, SeqAccess}};
|
||||
|
||||
use crate::data::{Data, DataKey};
|
||||
use crate::data::{BytesDeserializer, Data, DataKey, KeyDeserializer};
|
||||
|
||||
impl<'de> serde::Deserializer<'de> for &Data {
|
||||
type Error = serde::de::value::Error;
|
||||
impl<'de> Deserializer<'de> for &'de Data {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
Data::Boolean(b) => visitor.visit_bool(*b),
|
||||
Data::Integer(i) => visitor.visit_i64(*i),
|
||||
Data::Number(n) => visitor.visit_f64(*n),
|
||||
Data::String(s) => visitor.visit_str(s),
|
||||
Data::List(l) => visitor.visit_seq(DataSeqAccess { iter: l.iter() }),
|
||||
Data::Dict(d) => visitor.visit_map(DataMapAccess { iter: d.iter(), value: None }),
|
||||
Data::String(s) => visitor.visit_borrowed_str(s),
|
||||
Data::List(l) => visitor.visit_seq(SeqDeserializer { iter: l.iter() }),
|
||||
Data::Dict(d) => visitor.visit_map(MapDeserializer { iter: d.iter(), value: None }),
|
||||
Data::Id(i) => visitor.visit_u64(i.get()),
|
||||
Data::Url(_) => Err(Error::custom("url not supported")),
|
||||
Data::Url(u) => u.into_deserializer().deserialize_any(visitor),
|
||||
Data::Path(_) => Err(Error::custom("path not supported")),
|
||||
Data::Bytes(b) => visitor.visit_bytes(b),
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_any(visitor),
|
||||
Data::Any(_) => Err(Error::custom("any not supported")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_bool(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i8(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i16(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i32(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i64(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u8(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u16(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u32(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u64(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_f32(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_f64(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let s: &str = self.try_into().map_err(Error::custom)?;
|
||||
let mut chars = s.chars();
|
||||
|
|
@ -116,37 +116,41 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_str(self.try_into().map_err(Error::custom)?)
|
||||
visitor.visit_borrowed_str(self.try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let s: &str = self.try_into().map_err(Error::custom)?;
|
||||
visitor.visit_string(s.to_owned())
|
||||
match self {
|
||||
Data::Url(u) => visitor.visit_newtype_struct(u.into_deserializer()),
|
||||
_ => self.deserialize_str(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_bytes(self.try_into().map_err(Error::custom)?)
|
||||
match self {
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_bytes(visitor),
|
||||
_ => Err(Error::custom("not bytes")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let bytes: &[u8] = self.try_into().map_err(Error::custom)?;
|
||||
visitor.visit_byte_buf(bytes.to_vec())
|
||||
self.deserialize_bytes(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_none(),
|
||||
|
|
@ -156,7 +160,7 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
|
||||
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
|
|
@ -170,7 +174,7 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
|
|
@ -184,25 +188,25 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::List(l) => visitor.visit_seq(DataSeqAccess { iter: l.iter() }),
|
||||
Data::Bytes(b) => visitor.visit_seq(DataByteSeqAccess { iter: b.iter() }),
|
||||
Data::List(l) => visitor.visit_seq(SeqDeserializer { iter: l.iter() }),
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_seq(visitor),
|
||||
_ => Err(Error::custom("not a sequence")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
|
@ -214,19 +218,19 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
if let Data::Dict(d) = self {
|
||||
visitor.visit_map(DataMapAccess { iter: d.iter(), value: None })
|
||||
} else {
|
||||
Err(Error::custom("not a map"))
|
||||
match self {
|
||||
Data::Dict(d) => visitor.visit_map(MapDeserializer { iter: d.iter(), value: None }),
|
||||
Data::Url(u) => u.into_deserializer().deserialize_map(visitor),
|
||||
_ => Err(Error::custom("not a map")),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +241,7 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
|
@ -249,7 +253,7 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::String(s) => visitor.visit_enum((&**s).into_deserializer()),
|
||||
|
|
@ -259,29 +263,36 @@ impl<'de> serde::Deserializer<'de> for &Data {
|
|||
|
||||
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::custom("identifier not supported"))
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::custom("ignored any not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
struct DataSeqAccess<'a> {
|
||||
impl<'de> IntoDeserializer<'de, de::value::Error> for &'de Data {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer { self }
|
||||
}
|
||||
|
||||
// --- Seq
|
||||
struct SeqDeserializer<'a> {
|
||||
iter: std::slice::Iter<'a, Data>,
|
||||
}
|
||||
|
||||
impl<'de> SeqAccess<'de> for DataSeqAccess<'_> {
|
||||
type Error = serde::de::value::Error;
|
||||
impl<'de> SeqAccess<'de> for SeqDeserializer<'de> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.iter.next().map(|value| seed.deserialize(value)).transpose()
|
||||
}
|
||||
|
|
@ -289,51 +300,28 @@ impl<'de> SeqAccess<'de> for DataSeqAccess<'_> {
|
|||
fn size_hint(&self) -> Option<usize> { Some(self.iter.len()) }
|
||||
}
|
||||
|
||||
struct DataByteSeqAccess<'a> {
|
||||
iter: std::slice::Iter<'a, u8>,
|
||||
}
|
||||
|
||||
impl<'de> SeqAccess<'de> for DataByteSeqAccess<'_> {
|
||||
type Error = serde::de::value::Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: serde::de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.iter.next().map(|value| seed.deserialize((*value).into_deserializer())).transpose()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> { Some(self.iter.len()) }
|
||||
}
|
||||
|
||||
struct DataMapAccess<'a> {
|
||||
// --- Map
|
||||
struct MapDeserializer<'a> {
|
||||
iter: hashbrown::hash_map::Iter<'a, DataKey, Data>,
|
||||
value: Option<&'a Data>,
|
||||
}
|
||||
|
||||
impl<'de> MapAccess<'de> for DataMapAccess<'_> {
|
||||
type Error = serde::de::value::Error;
|
||||
impl<'de> MapAccess<'de> for MapDeserializer<'de> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: serde::de::DeserializeSeed<'de>,
|
||||
K: de::DeserializeSeed<'de>,
|
||||
{
|
||||
let Some((key, value)) = self.iter.next() else { return Ok(None) };
|
||||
self.value = Some(value);
|
||||
|
||||
match key {
|
||||
DataKey::Boolean(b) => seed.deserialize((*b).into_deserializer()).map(Some),
|
||||
DataKey::Integer(i) => seed.deserialize((*i).into_deserializer()).map(Some),
|
||||
DataKey::Number(n) => seed.deserialize((*n).into_deserializer()).map(Some),
|
||||
DataKey::String(s) => seed.deserialize((&**s).into_deserializer()).map(Some),
|
||||
DataKey::Id(id) => seed.deserialize(id.get().into_deserializer()).map(Some),
|
||||
_ => Err(Error::custom("unsupported map key type")),
|
||||
}
|
||||
seed.deserialize(KeyDeserializer::Borrowed(key)).map(Some)
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::DeserializeSeed<'de>,
|
||||
V: de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self.value.take().ok_or_else(|| Error::custom("value missing for key"))?)
|
||||
}
|
||||
|
|
|
|||
71
yazi-shared/src/data/de_bytes.rs
Normal file
71
yazi-shared/src/data/de_bytes.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use serde::{Deserializer, de::{self, value::SeqDeserializer}};
|
||||
|
||||
pub(crate) struct BytesDeserializer<'a>(pub(crate) Cow<'a, [u8]>);
|
||||
|
||||
impl<'de, 'a: 'de> Deserializer<'de> for BytesDeserializer<'a> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string unit unit_struct
|
||||
map struct enum bytes byte_buf identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self.0 {
|
||||
Cow::Borrowed(b) => visitor.visit_borrowed_bytes(b),
|
||||
Cow::Owned(b) => visitor.visit_byte_buf(b),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self.0 {
|
||||
Cow::Borrowed(b) => visitor.visit_seq(SeqDeserializer::new(b.iter().copied())),
|
||||
Cow::Owned(b) => visitor.visit_seq(SeqDeserializer::new(b.into_iter())),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
}
|
||||
114
yazi-shared/src/data/de_key.rs
Normal file
114
yazi-shared/src/data/de_key.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use std::{borrow::Cow, ops::Deref};
|
||||
|
||||
use serde::{Deserializer, de::{self, Error, IntoDeserializer}};
|
||||
|
||||
use crate::data::DataKey;
|
||||
|
||||
pub(crate) enum KeyDeserializer<'a> {
|
||||
Borrowed(&'a DataKey),
|
||||
Owned(DataKey),
|
||||
}
|
||||
|
||||
impl Deref for KeyDeserializer<'_> {
|
||||
type Target = DataKey;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Borrowed(key) => key,
|
||||
Self::Owned(key) => key,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a: 'de> Deserializer<'de> for KeyDeserializer<'a> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i128 u8 u16 u32 u128 f32 f64 char bytes byte_buf
|
||||
option unit unit_struct newtype_struct seq tuple tuple_struct map struct enum ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Self::Borrowed(DataKey::Boolean(b)) => visitor.visit_bool(*b),
|
||||
Self::Borrowed(DataKey::Integer(i)) => visitor.visit_i64(*i),
|
||||
Self::Borrowed(DataKey::Number(n)) => visitor.visit_f64(n.0),
|
||||
Self::Borrowed(DataKey::String(s)) => visitor.visit_borrowed_str(s),
|
||||
Self::Borrowed(DataKey::Id(id)) => visitor.visit_u64(id.get()),
|
||||
Self::Borrowed(DataKey::Url(u)) => u.into_deserializer().deserialize_any(visitor),
|
||||
Self::Owned(DataKey::Boolean(b)) => visitor.visit_bool(b),
|
||||
Self::Owned(DataKey::Integer(i)) => visitor.visit_i64(i),
|
||||
Self::Owned(DataKey::Number(n)) => visitor.visit_f64(n.0),
|
||||
Self::Owned(DataKey::String(Cow::Borrowed(s))) => visitor.visit_borrowed_str(s),
|
||||
Self::Owned(DataKey::String(Cow::Owned(s))) => visitor.visit_string(s),
|
||||
Self::Owned(DataKey::Id(id)) => visitor.visit_u64(id.get()),
|
||||
Self::Owned(DataKey::Url(u)) => u.into_deserializer().deserialize_any(visitor),
|
||||
_ => Err(Error::custom("unsupported map key type")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i64((&*self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u64((&*self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_identifier(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Self::Borrowed(DataKey::Url(u)) => visitor.visit_newtype_struct(u.into_deserializer()),
|
||||
Self::Owned(DataKey::Url(u)) => visitor.visit_newtype_struct(u.into_deserializer()),
|
||||
other => other.deserialize_str(visitor),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Self::Borrowed(DataKey::Boolean(b)) => {
|
||||
visitor.visit_borrowed_str(if *b { "true" } else { "false" })
|
||||
}
|
||||
Self::Borrowed(DataKey::Integer(i)) => visitor.visit_string(i.to_string()),
|
||||
Self::Borrowed(DataKey::Number(n)) => visitor.visit_string(n.0.to_string()),
|
||||
Self::Borrowed(DataKey::String(s)) => visitor.visit_borrowed_str(s),
|
||||
Self::Borrowed(DataKey::Id(id)) => visitor.visit_string(id.get().to_string()),
|
||||
Self::Owned(DataKey::Boolean(b)) => {
|
||||
visitor.visit_borrowed_str(if b { "true" } else { "false" })
|
||||
}
|
||||
Self::Owned(DataKey::Integer(i)) => visitor.visit_string(i.to_string()),
|
||||
Self::Owned(DataKey::Number(n)) => visitor.visit_string(n.0.to_string()),
|
||||
Self::Owned(DataKey::String(Cow::Borrowed(s))) => visitor.visit_borrowed_str(s),
|
||||
Self::Owned(DataKey::String(Cow::Owned(s))) => visitor.visit_string(s),
|
||||
Self::Owned(DataKey::Id(id)) => visitor.visit_string(id.get().to_string()),
|
||||
_ => Err(Error::custom("unsupported map key type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a: 'de> IntoDeserializer<'de, de::value::Error> for KeyDeserializer<'a> {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer { self }
|
||||
}
|
||||
335
yazi-shared/src/data/de_owned.rs
Normal file
335
yazi-shared/src/data/de_owned.rs
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use serde::{Deserializer, de::{self, Error, IntoDeserializer, MapAccess, SeqAccess}};
|
||||
|
||||
use crate::data::{BytesDeserializer, Data, DataKey, KeyDeserializer};
|
||||
|
||||
impl<'de> Deserializer<'de> for Data {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
Data::Boolean(b) => visitor.visit_bool(b),
|
||||
Data::Integer(i) => visitor.visit_i64(i),
|
||||
Data::Number(n) => visitor.visit_f64(n),
|
||||
Data::String(Cow::Borrowed(s)) => visitor.visit_borrowed_str(s),
|
||||
Data::String(Cow::Owned(s)) => visitor.visit_string(s),
|
||||
Data::List(l) => visitor.visit_seq(SeqDeserializer { iter: l.into_iter() }),
|
||||
Data::Dict(d) => visitor.visit_map(MapDeserializer { iter: d.into_iter(), value: None }),
|
||||
Data::Id(i) => visitor.visit_u64(i.get()),
|
||||
Data::Url(u) => u.into_deserializer().deserialize_any(visitor),
|
||||
Data::Path(_) => Err(Error::custom("path not supported")),
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_any(visitor),
|
||||
Data::Any(_) => Err(Error::custom("any not supported")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_bool((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i8((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i16((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i32((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_i64((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u8((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u16((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u32((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_u64((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_f32((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_f64((&self).try_into().map_err(Error::custom)?)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
let s: &str = (&self).try_into().map_err(Error::custom)?;
|
||||
let mut chars = s.chars();
|
||||
match (chars.next(), chars.next()) {
|
||||
(Some(ch), None) => visitor.visit_char(ch),
|
||||
_ => Err(Error::custom("not a char")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::String(Cow::Borrowed(s)) => visitor.visit_borrowed_str(s),
|
||||
Data::String(Cow::Owned(s)) => visitor.visit_string(s),
|
||||
Data::Url(u) => visitor.visit_newtype_struct(u.into_deserializer()),
|
||||
_ => Err(Error::custom("not a string")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_bytes(visitor),
|
||||
_ => Err(Error::custom("not bytes")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_bytes(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_none(),
|
||||
other => visitor.visit_some(other),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
_ => Err(Error::custom("expected unit")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Nil => visitor.visit_unit(),
|
||||
_ => Err(Error::custom("expected unit struct")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::List(l) => visitor.visit_seq(SeqDeserializer { iter: l.into_iter() }),
|
||||
Data::Bytes(b) => BytesDeserializer(b.into()).deserialize_seq(visitor),
|
||||
_ => Err(Error::custom("not a sequence")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::Dict(d) => visitor.visit_map(MapDeserializer { iter: d.into_iter(), value: None }),
|
||||
Data::Url(u) => Deserializer::deserialize_map(u.into_deserializer(), visitor),
|
||||
_ => Err(Error::custom("not a map")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
match self {
|
||||
Data::String(s) => visitor.visit_enum(s.into_deserializer()),
|
||||
_ => Err(Error::custom("not an enum")),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::custom("identifier not supported"))
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
Err(Error::custom("ignored any not supported"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> IntoDeserializer<'de, de::value::Error> for Data {
|
||||
type Deserializer = Self;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer { self }
|
||||
}
|
||||
|
||||
// --- Seq
|
||||
struct SeqDeserializer {
|
||||
iter: std::vec::IntoIter<Data>,
|
||||
}
|
||||
|
||||
impl<'de> SeqAccess<'de> for SeqDeserializer {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
self.iter.next().map(|value| seed.deserialize(value)).transpose()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> { Some(self.iter.len()) }
|
||||
}
|
||||
|
||||
// --- Map
|
||||
struct MapDeserializer {
|
||||
iter: hashbrown::hash_map::IntoIter<DataKey, Data>,
|
||||
value: Option<Data>,
|
||||
}
|
||||
|
||||
impl<'de> MapAccess<'de> for MapDeserializer {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: de::DeserializeSeed<'de>,
|
||||
{
|
||||
let Some((key, value)) = self.iter.next() else { return Ok(None) };
|
||||
self.value = Some(value);
|
||||
|
||||
seed.deserialize(KeyDeserializer::Owned(key)).map(Some)
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::DeserializeSeed<'de>,
|
||||
{
|
||||
seed.deserialize(self.value.take().ok_or_else(|| Error::custom("value missing for key"))?)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> { Some(self.iter.len()) }
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ use std::borrow::Cow;
|
|||
use ordered_float::OrderedFloat;
|
||||
use serde::{Deserialize, Serialize, de};
|
||||
|
||||
use crate::{Id, SStr, path::PathBufDyn, url::{UrlBuf, UrlCow}};
|
||||
use crate::{Id, SStr, path::PathBufDyn, url::UrlBuf};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[serde(untagged)]
|
||||
|
|
@ -33,15 +33,6 @@ impl DataKey {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn into_url(self) -> Option<UrlCow<'static>> {
|
||||
match self {
|
||||
Self::String(s) => s.try_into().ok(),
|
||||
Self::Url(u) => Some(u.into()),
|
||||
Self::Bytes(b) => b.try_into().ok(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_integer<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
|
|
@ -80,3 +71,6 @@ impl From<&'static str> for DataKey {
|
|||
impl From<String> for DataKey {
|
||||
fn from(value: String) -> Self { Self::String(Cow::Owned(value)) }
|
||||
}
|
||||
|
||||
impl_into_integer!(DataKey, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, crate::Id);
|
||||
impl_into_number!(DataKey, f32, f64);
|
||||
|
|
|
|||
62
yazi-shared/src/data/macros.rs
Normal file
62
yazi-shared/src/data/macros.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use anyhow::bail;
|
||||
|
||||
pub(crate) fn float_to_i64<T>(value: T) -> anyhow::Result<i64>
|
||||
where
|
||||
T: Into<f64>,
|
||||
{
|
||||
let value = value.into();
|
||||
if !value.is_finite() || value.fract() != 0.0 {
|
||||
bail!("not an integer");
|
||||
}
|
||||
|
||||
let integer = value as i64;
|
||||
if integer as f64 != value {
|
||||
bail!("not an integer");
|
||||
}
|
||||
|
||||
Ok(integer)
|
||||
}
|
||||
|
||||
macro_rules! impl_into_integer {
|
||||
($a:ty, $($b:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl TryFrom<&$a> for $b {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &$a) -> Result<Self, Self::Error> {
|
||||
paste::paste! {
|
||||
Ok(match value {
|
||||
$a::Integer(i) => <$b>::try_from(*i)?,
|
||||
$a::Number(n) => <$b>::try_from($crate::data::macros::float_to_i64(*n)?)?,
|
||||
$a::String(s) => s.parse()?,
|
||||
$a::Id(i) => <$b>::try_from(i.get())?,
|
||||
_ => anyhow::bail!("not an integer"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_into_number {
|
||||
($a:ty, $($b:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl TryFrom<&$a> for $b {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(value: &$a) -> Result<Self, Self::Error> {
|
||||
paste::paste! {
|
||||
Ok(match value {
|
||||
$a::Integer(i) if *i == (*i as $b as _) => *i as $b,
|
||||
$a::Number(n) if f64::from(*n) == (f64::from(*n) as $b as _) => f64::from(*n) as $b,
|
||||
$a::String(s) => s.parse()?,
|
||||
$a::Id(i) if i.get() == (i.get() as $b as _) => i.get() as $b,
|
||||
_ => anyhow::bail!("not a number"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
|
@ -1 +1,4 @@
|
|||
yazi_macro::mod_flat!(any data de key);
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
yazi_macro::mod_flat!(any data de de_bytes de_key de_owned key);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{iter, ops::Deref};
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::de::DeserializeOwned;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use super::Action;
|
||||
|
|
@ -36,6 +37,16 @@ impl From<&'static Action> for ActionCow {
|
|||
}
|
||||
|
||||
impl ActionCow {
|
||||
pub fn deserialize<T>(self) -> Result<T, serde::de::value::Error>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
match self {
|
||||
Self::Owned(c) => T::deserialize(c),
|
||||
Self::Borrowed(c) => T::deserialize(c),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take<'a, T>(&mut self, name: impl Into<DataKey>) -> Result<T>
|
||||
where
|
||||
T: TryFrom<Data> + TryFrom<&'a Data>,
|
||||
|
|
|
|||
43
yazi-shared/src/event/de.rs
Normal file
43
yazi-shared/src/event/de.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
use serde::de::value::MapDeserializer;
|
||||
|
||||
use super::Action;
|
||||
use crate::data::KeyDeserializer;
|
||||
|
||||
impl<'de> serde::Deserializer<'de> for &'de Action {
|
||||
type Error = serde::de::value::Error;
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf
|
||||
unit struct unit_struct newtype_struct seq tuple tuple_struct enum identifier
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(MapDeserializer::new(
|
||||
self.args.iter().map(|(key, value)| (KeyDeserializer::Borrowed(key), value)),
|
||||
))
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_unit()
|
||||
}
|
||||
}
|
||||
42
yazi-shared/src/event/de_owned.rs
Normal file
42
yazi-shared/src/event/de_owned.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use serde::de::value::MapDeserializer;
|
||||
|
||||
use crate::{data::KeyDeserializer, event::Action};
|
||||
|
||||
impl<'de> serde::Deserializer<'de> for Action {
|
||||
type Error = serde::de::value::Error;
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf
|
||||
unit struct unit_struct newtype_struct seq tuple tuple_struct enum identifier
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(MapDeserializer::new(
|
||||
self.args.into_iter().map(|(key, value)| (KeyDeserializer::Owned(key), value)),
|
||||
))
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_unit()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
yazi_macro::mod_flat!(action cow event);
|
||||
yazi_macro::mod_flat!(action cow de de_owned event);
|
||||
|
||||
pub static NEED_RENDER: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
|
||||
|
|
|
|||
124
yazi-shared/src/loc/cow.rs
Normal file
124
yazi-shared/src/loc/cow.rs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
use std::{borrow::Cow, fmt::{self, Debug}};
|
||||
|
||||
use crate::{loc::{Loc, LocAble, LocAbleImpl, LocBuf, LocBufAble}, path::{PathBufDyn, PathCow, PathDyn}};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum LocCow<'a, B = &'a std::path::Path, O = std::path::PathBuf>
|
||||
where
|
||||
B: LocAble<'a, Owned = O>,
|
||||
O: LocBufAble,
|
||||
{
|
||||
Borrowed(Loc<'a, B>),
|
||||
Owned(LocBuf<O>),
|
||||
}
|
||||
|
||||
impl<'a, B, O> Debug for LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O>,
|
||||
O: LocBufAble,
|
||||
Loc<'a, B>: Debug,
|
||||
LocBuf<O>: Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Borrowed(loc) => f.debug_tuple("Borrowed").field(loc).finish(),
|
||||
Self::Owned(loc) => f.debug_tuple("Owned").field(loc).finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B, O> Default for LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O> + LocAbleImpl<'a>,
|
||||
O: LocBufAble,
|
||||
{
|
||||
fn default() -> Self { Self::Borrowed(Default::default()) }
|
||||
}
|
||||
|
||||
impl<'a, B, O> From<Loc<'a, B>> for LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O>,
|
||||
O: LocBufAble,
|
||||
{
|
||||
fn from(value: Loc<'a, B>) -> Self { Self::Borrowed(value) }
|
||||
}
|
||||
|
||||
impl<'a, B, O> From<LocBuf<O>> for LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O>,
|
||||
O: LocBufAble,
|
||||
{
|
||||
fn from(value: LocBuf<O>) -> Self { Self::Owned(value) }
|
||||
}
|
||||
|
||||
impl<'a, B, O> From<LocCow<'a, B, O>> for PathCow<'a>
|
||||
where
|
||||
B: LocAble<'a, Owned = O> + Into<PathDyn<'a>>,
|
||||
O: LocBufAble + Into<PathBufDyn>,
|
||||
{
|
||||
fn from(value: LocCow<'a, B, O>) -> Self { value.into_path() }
|
||||
}
|
||||
|
||||
impl<'a> LocCow<'a> {
|
||||
pub fn as_loc(&self) -> Loc<'_> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => *loc,
|
||||
Self::Owned(loc) => loc.as_loc(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Cow<'a, std::path::Path> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => Cow::Borrowed(loc.as_inner()),
|
||||
Self::Owned(loc) => Cow::Owned(loc.into_inner()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LocCow<'a, &'a typed_path::UnixPath, typed_path::UnixPathBuf> {
|
||||
pub fn as_loc(&self) -> Loc<'_, &'_ typed_path::UnixPath> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => *loc,
|
||||
Self::Owned(loc) => loc.as_loc(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Cow<'a, typed_path::UnixPath> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => Cow::Borrowed(loc.as_inner()),
|
||||
Self::Owned(loc) => Cow::Owned(loc.into_inner()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, B, O> LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O> + LocAbleImpl<'a>,
|
||||
O: LocBufAble,
|
||||
{
|
||||
pub fn into_owned(self) -> LocBuf<O> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => {
|
||||
LocBuf { inner: loc.inner.to_path_buf(), uri: loc.uri, urn: loc.urn }
|
||||
}
|
||||
Self::Owned(loc) => loc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_borrowed(&self) -> bool { matches!(self, Self::Borrowed(_)) }
|
||||
|
||||
pub fn is_owned(&self) -> bool { !self.is_borrowed() }
|
||||
}
|
||||
|
||||
impl<'a, B, O> LocCow<'a, B, O>
|
||||
where
|
||||
B: LocAble<'a, Owned = O> + Into<PathDyn<'a>>,
|
||||
O: LocBufAble + Into<PathBufDyn>,
|
||||
{
|
||||
pub fn into_path(self) -> PathCow<'a> {
|
||||
match self {
|
||||
Self::Borrowed(loc) => PathCow::Borrowed(loc.inner.into()),
|
||||
Self::Owned(loc) => PathCow::Owned(loc.inner.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
#![allow(private_bounds)]
|
||||
|
||||
yazi_macro::mod_flat!(able buf loc);
|
||||
yazi_macro::mod_flat!(able buf cow loc);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use anyhow::Result;
|
|||
|
||||
use crate::path::{AsPath, PathBufDyn, PathDyn, PathDynError, PathKind};
|
||||
|
||||
// --- PathCow
|
||||
#[derive(Debug)]
|
||||
pub enum PathCow<'a> {
|
||||
Borrowed(PathDyn<'a>),
|
||||
|
|
@ -45,6 +44,13 @@ impl PartialEq<&str> for PathCow<'_> {
|
|||
}
|
||||
|
||||
impl<'a> PathCow<'a> {
|
||||
pub fn into_encoded_bytes(self) -> Cow<'a, [u8]> {
|
||||
match self {
|
||||
Self::Borrowed(p) => Cow::Borrowed(p.encoded_bytes()),
|
||||
Self::Owned(p) => Cow::Owned(p.into_encoded_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> PathBufDyn {
|
||||
match self {
|
||||
Self::Borrowed(p) => p.to_owned(),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::{hash::{Hash, Hasher}, marker::PhantomData, mem::ManuallyDrop, ops::Deref, str};
|
||||
use std::{borrow::Cow, hash::{Hash, Hasher}, marker::PhantomData, mem::ManuallyDrop, ops::Deref, str};
|
||||
|
||||
use hashbrown::hash_map::RawEntryMut;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::pool::{Pool, SYMBOLS, SymbolPtr, compute_hash};
|
||||
|
||||
|
|
@ -133,6 +134,15 @@ impl std::fmt::Debug for Symbol<str> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Symbol<str> {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
Cow::<str>::deserialize(deserializer).map(Pool::<str>::intern)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Symbol<T> {
|
||||
#[inline]
|
||||
pub(super) fn new(ptr: SymbolPtr) -> Self { Self { ptr, _phantom: PhantomData } }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use anyhow::{Result, bail};
|
||||
use strum::IntoStaticStr;
|
||||
|
||||
use crate::{BytesExt, scheme::{AsScheme, SchemeRef}};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, IntoStaticStr)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum SchemeKind {
|
||||
Regular,
|
||||
Search,
|
||||
|
|
@ -39,16 +41,6 @@ impl TryFrom<&[u8]> for SchemeKind {
|
|||
}
|
||||
|
||||
impl SchemeKind {
|
||||
#[inline]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Regular => "regular",
|
||||
Self::Search => "search",
|
||||
Self::Archive => "archive",
|
||||
Self::Sftp => "sftp",
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_local(self) -> bool {
|
||||
match self {
|
||||
|
|
@ -74,8 +66,8 @@ impl SchemeKind {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) const fn offset(self, tilde: bool) -> usize {
|
||||
3 + self.as_str().len() + tilde as usize
|
||||
pub(super) fn offset(self, tilde: bool) -> usize {
|
||||
3 + Into::<&str>::into(self).len() + tilde as usize
|
||||
}
|
||||
|
||||
pub fn parse(bytes: &[u8]) -> Result<Option<(Self, bool)>> {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ pub enum SchemeRef<'a> {
|
|||
impl Deref for SchemeRef<'_> {
|
||||
type Target = SchemeKind;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Regular { .. } => &SchemeKind::Regular,
|
||||
|
|
@ -42,13 +41,11 @@ impl From<SchemeRef<'_>> for Scheme {
|
|||
}
|
||||
|
||||
impl<'a> SchemeRef<'a> {
|
||||
#[inline]
|
||||
pub fn covariant(self, other: impl AsScheme) -> bool {
|
||||
let other = other.as_scheme();
|
||||
if self.is_virtual() || other.is_virtual() { self == other } else { true }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn domain(self) -> Option<&'a str> {
|
||||
match self {
|
||||
Self::Regular { .. } => None,
|
||||
|
|
@ -58,7 +55,6 @@ impl<'a> SchemeRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn kind(self) -> SchemeKind {
|
||||
match self {
|
||||
Self::Regular { .. } => SchemeKind::Regular,
|
||||
|
|
@ -68,7 +64,6 @@ impl<'a> SchemeRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn ports(self) -> (usize, usize) {
|
||||
match self {
|
||||
Self::Regular { uri, urn } => (uri, urn),
|
||||
|
|
@ -96,6 +91,5 @@ impl<'a> SchemeRef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn zeroed(self) -> Self { self.with_ports(0, 0) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{pool::Symbol, scheme::{AsScheme, SchemeRef}};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||
#[serde(tag = "kind", rename_all = "kebab-case")]
|
||||
pub enum Scheme {
|
||||
Regular { uri: usize, urn: usize },
|
||||
Search { domain: Symbol<str>, uri: usize, urn: usize },
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ where
|
|||
{
|
||||
fn kind(&self) -> SchemeKind { *self.as_scheme() }
|
||||
|
||||
fn ports(&self) -> (usize, usize) { self.as_scheme().ports() }
|
||||
|
||||
fn domain(&self) -> Option<&str> { self.as_scheme().domain() }
|
||||
|
||||
fn covariant(&self, other: impl AsScheme) -> bool { self.as_scheme().covariant(other) }
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::{borrow::Cow, fmt::{Debug, Formatter}, hash::{Hash, Hasher}, path::{Path, PathBuf}, str::FromStr};
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize, de::{self, IntoDeserializer}};
|
||||
|
||||
use crate::{loc::LocBuf, path::{PathBufDyn, PathDynError, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::Scheme, strand::AsStrand, url::{AsUrl, Url, UrlCow, UrlLike}};
|
||||
use crate::{loc::LocBuf, path::{PathBufDyn, PathDynError, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::{Scheme, SchemeLike}, strand::AsStrand, url::{AsUrl, Url, UrlCow, UrlDeserializer, UrlLike}};
|
||||
|
||||
#[derive(Clone, Eq)]
|
||||
pub enum UrlBuf {
|
||||
|
|
@ -203,11 +203,63 @@ impl<'de> Deserialize<'de> for UrlBuf {
|
|||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
Self::try_from(s).map_err(serde::de::Error::custom)
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for Visitor {
|
||||
type Value = UrlBuf;
|
||||
|
||||
fn expecting(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
formatter.write_str("a Url or URL string")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
UrlBuf::from_str(value).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
UrlBuf::try_from(value).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Shadow {
|
||||
#[serde(flatten)]
|
||||
scheme: Scheme,
|
||||
path: Vec<u8>,
|
||||
}
|
||||
|
||||
let Shadow { scheme, path } = Deserialize::deserialize(deserializer)?;
|
||||
let path = PathBufDyn::with(scheme.kind(), path).map_err(de::Error::custom)?;
|
||||
|
||||
UrlBuf::try_from((scheme, path)).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_string(Visitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> IntoDeserializer<'de, de::value::Error> for UrlBuf {
|
||||
type Deserializer = UrlDeserializer<'de>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer { UrlDeserializer(self.into()) }
|
||||
}
|
||||
|
||||
impl<'de> IntoDeserializer<'de, de::value::Error> for &'de UrlBuf {
|
||||
type Deserializer = UrlDeserializer<'de>;
|
||||
|
||||
fn into_deserializer(self) -> Self::Deserializer { UrlDeserializer(self.into()) }
|
||||
}
|
||||
|
||||
// --- Tests
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
|||
|
|
@ -2,34 +2,30 @@ use std::{borrow::Cow, hash::{Hash, Hasher}, path::PathBuf};
|
|||
|
||||
use anyhow::{Result, anyhow};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use typed_path::{UnixPath, UnixPathBuf};
|
||||
|
||||
use crate::{loc::{Loc, LocBuf}, path::{PathBufDyn, PathCow, PathDyn}, pool::SymbolCow, scheme::{AsScheme, Scheme, SchemeCow, SchemeKind, SchemeRef}, url::{AsUrl, Url, UrlBuf}};
|
||||
use crate::{loc::{Loc, LocBuf, LocCow}, path::{PathBufDyn, PathCow, PathDyn}, pool::SymbolCow, scheme::{AsScheme, Scheme, SchemeCow, SchemeKind, SchemeRef}, url::{AsUrl, Url, UrlBuf}};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum UrlCow<'a> {
|
||||
Regular(LocBuf),
|
||||
Search { loc: LocBuf, domain: SymbolCow<'a, str> },
|
||||
Archive { loc: LocBuf, domain: SymbolCow<'a, str> },
|
||||
Sftp { loc: LocBuf<typed_path::UnixPathBuf>, domain: SymbolCow<'a, str> },
|
||||
|
||||
RegularRef(Loc<'a>),
|
||||
SearchRef { loc: Loc<'a>, domain: SymbolCow<'a, str> },
|
||||
ArchiveRef { loc: Loc<'a>, domain: SymbolCow<'a, str> },
|
||||
SftpRef { loc: Loc<'a, &'a typed_path::UnixPath>, domain: SymbolCow<'a, str> },
|
||||
Regular(LocCow<'a>),
|
||||
Search { loc: LocCow<'a>, domain: SymbolCow<'a, str> },
|
||||
Archive { loc: LocCow<'a>, domain: SymbolCow<'a, str> },
|
||||
Sftp { loc: LocCow<'a, &'a UnixPath, UnixPathBuf>, domain: SymbolCow<'a, str> },
|
||||
}
|
||||
|
||||
// FIXME: remove
|
||||
impl Default for UrlCow<'_> {
|
||||
fn default() -> Self { Self::RegularRef(Default::default()) }
|
||||
fn default() -> Self { Self::Regular(Default::default()) }
|
||||
}
|
||||
|
||||
impl<'a> From<Url<'a>> for UrlCow<'a> {
|
||||
fn from(value: Url<'a>) -> Self {
|
||||
match value {
|
||||
Url::Regular(loc) => Self::RegularRef(loc),
|
||||
Url::Search { loc, domain } => Self::SearchRef { loc, domain: domain.into() },
|
||||
Url::Archive { loc, domain } => Self::ArchiveRef { loc, domain: domain.into() },
|
||||
Url::Sftp { loc, domain } => Self::SftpRef { loc, domain: domain.into() },
|
||||
Url::Regular(loc) => Self::Regular(loc.into()),
|
||||
Url::Search { loc, domain } => Self::Search { loc: loc.into(), domain: domain.into() },
|
||||
Url::Archive { loc, domain } => Self::Archive { loc: loc.into(), domain: domain.into() },
|
||||
Url::Sftp { loc, domain } => Self::Sftp { loc: loc.into(), domain: domain.into() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,10 +40,12 @@ where
|
|||
impl From<UrlBuf> for UrlCow<'_> {
|
||||
fn from(value: UrlBuf) -> Self {
|
||||
match value {
|
||||
UrlBuf::Regular(loc) => Self::Regular(loc),
|
||||
UrlBuf::Search { loc, domain } => Self::Search { loc, domain: domain.into() },
|
||||
UrlBuf::Archive { loc, domain } => Self::Archive { loc, domain: domain.into() },
|
||||
UrlBuf::Sftp { loc, domain } => Self::Sftp { loc, domain: domain.into() },
|
||||
UrlBuf::Regular(loc) => Self::Regular(loc.into()),
|
||||
UrlBuf::Search { loc, domain } => Self::Search { loc: loc.into(), domain: domain.into() },
|
||||
UrlBuf::Archive { loc, domain } => {
|
||||
Self::Archive { loc: loc.into(), domain: domain.into() }
|
||||
}
|
||||
UrlBuf::Sftp { loc, domain } => Self::Sftp { loc: loc.into(), domain: domain.into() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -146,17 +144,17 @@ impl<'a> TryFrom<(SchemeCow<'a>, PathDyn<'a>)> for UrlCow<'a> {
|
|||
let (uri, urn) = scheme.as_scheme().ports();
|
||||
let domain = scheme.into_domain();
|
||||
Ok(match kind {
|
||||
SchemeKind::Regular => Self::RegularRef(Loc::bare(path.as_os()?)),
|
||||
SchemeKind::Search => Self::SearchRef {
|
||||
loc: Loc::with(path.as_os()?, uri, urn)?,
|
||||
SchemeKind::Regular => Self::Regular(Loc::bare(path.as_os()?).into()),
|
||||
SchemeKind::Search => Self::Search {
|
||||
loc: Loc::with(path.as_os()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for search scheme"))?,
|
||||
},
|
||||
SchemeKind::Archive => Self::ArchiveRef {
|
||||
loc: Loc::with(path.as_os()?, uri, urn)?,
|
||||
SchemeKind::Archive => Self::Archive {
|
||||
loc: Loc::with(path.as_os()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for archive scheme"))?,
|
||||
},
|
||||
SchemeKind::Sftp => Self::SftpRef {
|
||||
loc: Loc::with(path.as_unix()?, uri, urn)?,
|
||||
SchemeKind::Sftp => Self::Sftp {
|
||||
loc: Loc::with(path.as_unix()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for sftp scheme"))?,
|
||||
},
|
||||
})
|
||||
|
|
@ -171,17 +169,19 @@ impl<'a> TryFrom<(SchemeCow<'a>, PathBufDyn)> for UrlCow<'a> {
|
|||
let (uri, urn) = scheme.as_scheme().ports();
|
||||
let domain = scheme.into_domain();
|
||||
Ok(match kind {
|
||||
SchemeKind::Regular => Self::Regular(path.into_os()?.into()),
|
||||
SchemeKind::Regular => {
|
||||
Self::Regular(LocBuf::<std::path::PathBuf>::from(path.into_os()?).into())
|
||||
}
|
||||
SchemeKind::Search => Self::Search {
|
||||
loc: LocBuf::<std::path::PathBuf>::with(path.try_into()?, uri, urn)?,
|
||||
loc: LocBuf::<std::path::PathBuf>::with(path.try_into()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for search scheme"))?,
|
||||
},
|
||||
SchemeKind::Archive => Self::Archive {
|
||||
loc: LocBuf::<std::path::PathBuf>::with(path.try_into()?, uri, urn)?,
|
||||
loc: LocBuf::<std::path::PathBuf>::with(path.try_into()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for archive scheme"))?,
|
||||
},
|
||||
SchemeKind::Sftp => Self::Sftp {
|
||||
loc: LocBuf::<typed_path::UnixPathBuf>::with(path.try_into()?, uri, urn)?,
|
||||
loc: LocBuf::<UnixPathBuf>::with(path.try_into()?, uri, urn)?.into(),
|
||||
domain: domain.ok_or_else(|| anyhow!("missing domain for sftp scheme"))?,
|
||||
},
|
||||
})
|
||||
|
|
@ -207,75 +207,75 @@ impl Hash for UrlCow<'_> {
|
|||
impl<'a> UrlCow<'a> {
|
||||
pub fn is_owned(&self) -> bool {
|
||||
match self {
|
||||
Self::Regular(_) | Self::Search { .. } | Self::Archive { .. } | Self::Sftp { .. } => true,
|
||||
Self::RegularRef(_)
|
||||
| Self::SearchRef { .. }
|
||||
| Self::ArchiveRef { .. }
|
||||
| Self::SftpRef { .. } => false,
|
||||
Self::Regular(loc) => loc.is_owned(),
|
||||
Self::Search { loc, .. } => loc.is_owned(),
|
||||
Self::Archive { loc, .. } => loc.is_owned(),
|
||||
Self::Sftp { loc, .. } => loc.is_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_owned(self) -> UrlBuf {
|
||||
match self {
|
||||
Self::Regular(loc) => UrlBuf::Regular(loc),
|
||||
Self::Search { loc, domain } => UrlBuf::Search { loc, domain: domain.into() },
|
||||
Self::Archive { loc, domain } => UrlBuf::Archive { loc, domain: domain.into() },
|
||||
Self::Sftp { loc, domain } => UrlBuf::Sftp { loc, domain: domain.into() },
|
||||
|
||||
Self::RegularRef(loc) => UrlBuf::Regular(loc.into()),
|
||||
Self::SearchRef { loc, domain } => {
|
||||
UrlBuf::Search { loc: loc.into(), domain: domain.into() }
|
||||
Self::Regular(loc) => UrlBuf::Regular(loc.into_owned()),
|
||||
Self::Search { loc, domain } => {
|
||||
UrlBuf::Search { loc: loc.into_owned(), domain: domain.into() }
|
||||
}
|
||||
Self::ArchiveRef { loc, domain } => {
|
||||
UrlBuf::Archive { loc: loc.into(), domain: domain.into() }
|
||||
Self::Archive { loc, domain } => {
|
||||
UrlBuf::Archive { loc: loc.into_owned(), domain: domain.into() }
|
||||
}
|
||||
Self::Sftp { loc, domain } => {
|
||||
UrlBuf::Sftp { loc: loc.into_owned(), domain: domain.into() }
|
||||
}
|
||||
Self::SftpRef { loc, domain } => UrlBuf::Sftp { loc: loc.into(), domain: domain.into() },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_scheme(self) -> SchemeCow<'a> {
|
||||
pub fn into_pair(self) -> (SchemeCow<'a>, PathCow<'a>) {
|
||||
let (uri, urn) = self.as_url().scheme().ports();
|
||||
match self {
|
||||
Self::Regular(_) => Scheme::Regular { uri, urn }.into(),
|
||||
Self::RegularRef(_) => SchemeRef::Regular { uri, urn }.into(),
|
||||
Self::Search { domain, .. } | Self::SearchRef { domain, .. } => match domain {
|
||||
SymbolCow::Borrowed(domain) => SchemeRef::Search { domain, uri, urn }.into(),
|
||||
SymbolCow::Owned(domain) => Scheme::Search { domain, uri, urn }.into(),
|
||||
Self::Regular(loc) => match loc {
|
||||
LocCow::Borrowed(_) => (SchemeRef::Regular { uri, urn }.into(), loc.into_path()),
|
||||
LocCow::Owned(_) => (Scheme::Regular { uri, urn }.into(), loc.into_path()),
|
||||
},
|
||||
Self::Archive { domain, .. } | Self::ArchiveRef { domain, .. } => match domain {
|
||||
SymbolCow::Borrowed(domain) => SchemeRef::Archive { domain, uri, urn }.into(),
|
||||
SymbolCow::Owned(domain) => Scheme::Archive { domain, uri, urn }.into(),
|
||||
Self::Search { loc, domain } => match domain {
|
||||
SymbolCow::Borrowed(domain) => {
|
||||
(SchemeRef::Search { domain, uri, urn }.into(), loc.into_path())
|
||||
}
|
||||
SymbolCow::Owned(domain) => (Scheme::Search { domain, uri, urn }.into(), loc.into_path()),
|
||||
},
|
||||
Self::Sftp { domain, .. } | Self::SftpRef { domain, .. } => match domain {
|
||||
SymbolCow::Borrowed(domain) => SchemeRef::Sftp { domain, uri, urn }.into(),
|
||||
SymbolCow::Owned(domain) => Scheme::Sftp { domain, uri, urn }.into(),
|
||||
Self::Archive { loc, domain } => match domain {
|
||||
SymbolCow::Borrowed(domain) => {
|
||||
(SchemeRef::Archive { domain, uri, urn }.into(), loc.into_path())
|
||||
}
|
||||
SymbolCow::Owned(domain) => (Scheme::Archive { domain, uri, urn }.into(), loc.into_path()),
|
||||
},
|
||||
Self::Sftp { loc, domain } => match domain {
|
||||
SymbolCow::Borrowed(domain) => {
|
||||
(SchemeRef::Sftp { domain, uri, urn }.into(), loc.into_path())
|
||||
}
|
||||
SymbolCow::Owned(domain) => (Scheme::Sftp { domain, uri, urn }.into(), loc.into_path()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_scheme(self) -> SchemeCow<'a> { self.into_pair().0 }
|
||||
|
||||
pub fn into_path(self) -> PathCow<'a> { self.into_pair().1 }
|
||||
|
||||
pub fn into_static(self) -> UrlCow<'static> {
|
||||
match self {
|
||||
UrlCow::Regular(loc) => UrlCow::Regular(loc),
|
||||
UrlCow::Search { loc, domain } => UrlCow::Search { loc, domain: domain.into_owned().into() },
|
||||
UrlCow::Regular(loc) => UrlCow::Regular(loc.into_owned().into()),
|
||||
UrlCow::Search { loc, domain } => {
|
||||
UrlCow::Search { loc: loc.into_owned().into(), domain: domain.into_owned().into() }
|
||||
}
|
||||
UrlCow::Archive { loc, domain } => {
|
||||
UrlCow::Archive { loc, domain: domain.into_owned().into() }
|
||||
UrlCow::Archive { loc: loc.into_owned().into(), domain: domain.into_owned().into() }
|
||||
}
|
||||
UrlCow::Sftp { loc, domain } => UrlCow::Sftp { loc, domain: domain.into_owned().into() },
|
||||
|
||||
UrlCow::RegularRef(loc) => UrlCow::Regular(loc.into()),
|
||||
UrlCow::SearchRef { loc, domain } => {
|
||||
UrlCow::Search { loc: loc.into(), domain: domain.into_owned().into() }
|
||||
}
|
||||
UrlCow::ArchiveRef { loc, domain } => {
|
||||
UrlCow::Archive { loc: loc.into(), domain: domain.into_owned().into() }
|
||||
}
|
||||
UrlCow::SftpRef { loc, domain } => {
|
||||
UrlCow::Sftp { loc: loc.into(), domain: domain.into_owned().into() }
|
||||
UrlCow::Sftp { loc, domain } => {
|
||||
UrlCow::Sftp { loc: loc.into_owned().into(), domain: domain.into_owned().into() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_owned(&self) -> UrlBuf { self.as_url().into() }
|
||||
}
|
||||
|
||||
|
|
|
|||
113
yazi-shared/src/url/de.rs
Normal file
113
yazi-shared/src/url/de.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use serde::{Deserializer, de::{self, IntoDeserializer, MapAccess}};
|
||||
|
||||
use crate::{data::BytesDeserializer, pool::SymbolCow, scheme::SchemeLike, url::UrlCow};
|
||||
|
||||
pub struct UrlDeserializer<'a>(pub(super) UrlCow<'a>);
|
||||
|
||||
impl<'de, 'a: 'de> Deserializer<'de> for UrlDeserializer<'a> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
serde::forward_to_deserialize_any! {
|
||||
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf option
|
||||
unit unit_struct struct newtype_struct seq tuple tuple_struct enum identifier ignored_any
|
||||
}
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::Visitor<'de>,
|
||||
{
|
||||
visitor.visit_map(MapDeserializer::new(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Map
|
||||
struct MapDeserializer<'a> {
|
||||
kind: Option<&'static str>,
|
||||
domain: Option<SymbolCow<'a, str>>,
|
||||
uri: Option<usize>,
|
||||
urn: Option<usize>,
|
||||
path: Option<Cow<'a, [u8]>>,
|
||||
}
|
||||
|
||||
impl<'a> MapDeserializer<'a> {
|
||||
fn new(url: UrlCow<'a>) -> Self {
|
||||
let (scheme, path) = url.into_pair();
|
||||
let kind: &'static str = scheme.kind().into();
|
||||
let (uri, urn) = scheme.ports();
|
||||
|
||||
Self {
|
||||
kind: Some(kind),
|
||||
domain: scheme.into_domain(),
|
||||
uri: Some(uri),
|
||||
urn: Some(urn),
|
||||
path: Some(path.into_encoded_bytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, 'a: 'de> MapAccess<'de> for MapDeserializer<'a> {
|
||||
type Error = de::value::Error;
|
||||
|
||||
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
|
||||
where
|
||||
K: de::DeserializeSeed<'de>,
|
||||
{
|
||||
let key = if self.kind.is_some() {
|
||||
Some("kind")
|
||||
} else if self.domain.is_some() {
|
||||
Some("domain")
|
||||
} else if self.uri.is_some() {
|
||||
Some("uri")
|
||||
} else if self.urn.is_some() {
|
||||
Some("urn")
|
||||
} else if self.path.is_some() {
|
||||
Some("path")
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
key.map(|key| seed.deserialize(key.into_deserializer())).transpose()
|
||||
}
|
||||
|
||||
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: de::DeserializeSeed<'de>,
|
||||
{
|
||||
if let Some(kind) = self.kind.take() {
|
||||
return seed.deserialize(kind.into_deserializer());
|
||||
}
|
||||
if let Some(domain) = self.domain.take() {
|
||||
return seed.deserialize(domain.as_ref().into_deserializer());
|
||||
}
|
||||
if let Some(uri) = self.uri.take() {
|
||||
return seed.deserialize(uri.into_deserializer());
|
||||
}
|
||||
if let Some(urn) = self.urn.take() {
|
||||
return seed.deserialize(urn.into_deserializer());
|
||||
}
|
||||
if let Some(path) = self.path.take() {
|
||||
return seed.deserialize(BytesDeserializer(path));
|
||||
}
|
||||
|
||||
Err(de::Error::custom("value missing for key"))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
Some(
|
||||
self.kind.is_some() as usize
|
||||
+ self.domain.is_some() as usize
|
||||
+ self.uri.is_some() as usize
|
||||
+ self.urn.is_some() as usize
|
||||
+ self.path.is_some() as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(buf component components cov cow display encode like traits url);
|
||||
yazi_macro::mod_flat!(buf component components cov cow de display encode like traits url);
|
||||
|
|
|
|||
|
|
@ -61,11 +61,6 @@ impl AsUrl for UrlCow<'_> {
|
|||
Self::Search { loc, domain } => Url::Search { loc: loc.as_loc(), domain },
|
||||
Self::Archive { loc, domain } => Url::Archive { loc: loc.as_loc(), domain },
|
||||
Self::Sftp { loc, domain } => Url::Sftp { loc: loc.as_loc(), domain },
|
||||
|
||||
Self::RegularRef(loc) => Url::Regular(*loc),
|
||||
Self::SearchRef { loc, domain } => Url::Search { loc: *loc, domain },
|
||||
Self::ArchiveRef { loc, domain } => Url::Archive { loc: *loc, domain },
|
||||
Self::SftpRef { loc, domain } => Url::Sftp { loc: *loc, domain },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue