Crate envpath

source ·
Expand description

envpath

A library for parsing and deserializing paths with special rules.

Features:

  • A struct EnvPath for representing system paths. raw is the special rule path(vector), while path is the normal path after parsing. Since Deref is implemented, you can use it just like Path of std.

The library also supports optional features for getting common system paths:

  • consts - Gets the value of some specific constants built into crate.
  • project - For generating project directories (user-specific data dir)
  • dirs - Provides standard directories on different platforms.

Serialization and deserialization

If you want to serialize/deserialize a configuration file, you need to enable the serde feature of envpath and add serde, as well as other related dependencies.

Next, we will add a ron dependency (You can actually use formats such as yaml or json, but you need to add the relevant dependencies instead of using ron.)

cargo add envpath --features=serde
cargo add serde --features=derive
cargo add ron

Serialization

Now let’s try serialization.

        use envpath::EnvPath;
        use serde::{Deserialize, Serialize};

        #[derive(Debug, Default, Serialize, Deserialize)]
        #[serde(default)]
        struct Cfg<'a> {
            dir: Option<EnvPath<'a>>,
        }

        let dir = Some(EnvPath::from([
            "$env: user ?? userprofile ?? home",
        ]));

        let ron_str = ron::to_string(&Cfg { dir }).expect("Failed to ser");
        println!("{ron_str}");

        std::fs::write("test.ron", ron_str)
            .expect("Failed to write the ron cfg to test.ron");

The output result is: (dir: Some(["$env: user ?? userprofile ?? home"]))

It looks like the structure is the same as before serialization, except for the additional dir key.

Yes, after serialization, it looks like that.

This path format is suitable for cross-platform use.

Since environment variables and other things may be dynamically changed.

Keeping the raw format during serialization and obtaining its true path during deserialization is reasonable.

If you want to save performance overhead, you can change the value of dir to None, and serde should skip it during serialization.

Deserialization

Next, let’s try deserialization!

        use envpath::EnvPath;
        use serde::{Deserialize, Serialize};
        use std::fs::File;

        #[derive(Debug, Default, Serialize, Deserialize)]
        #[serde(default)]
        struct Cfg<'a> {
            dir: Option<EnvPath<'a>>,
        }

        let cfg: Cfg = ron::de::from_reader(
            File::open("test.ron").expect("Failed to open the file: text.ron"),
        )
        .expect("Failed to deser ron cfg");

        dbg!(&cfg);

        if let Some(x) = cfg.dir {
            if x.exists() {
                println!("{}", x.display())
            }
        }

The output result of the above function is:

[src/lib.rs:116] &cfg = Cfg {
    dir: Some(
        EnvPath {
            raw: [
                "$env: user ?? userprofile ?? home",
            ],
            path: Some(
                "/home/m",
            ),
        },
    ),
}
/home/m

The ? operator checks if a value exists. If it doesn’t exist, continue checking. If it exists, use that value.

On the other hand, the ?? operator requires both the value and the path to exist.

For example, consider $env: user ? userprofile. Let’s assume that the value of user is m, and userprofile is empty. Since the value of user exists, the expression returns m.

If we change it to $env: user ?? userprofile ? home, even though the value of user exists, its path does not. So we continue checking. Then, since the value of userprofile does not exist, we continue checking until the condition is satisfied.

? and ?? have different functions, and adding ?? does not mean that you can discard ?. For values that are normal strings, such as $const: os, rather than paths, ? is more useful than ??. Each one has an important role to play.

const

Use $const:name (such as $const:arch) or $const:alias (e.g. $const:architecture) to obtain constant values. These values are obtained at compile time rather than runtime.

namealiasFromexample
archarchitectureconsts::ARCHx86_64, aarch64
deb-archdeb_archget_deb_arch()amd64, arm64
osconsts::OSlinux, windows, android
familyconsts::FAMILYunix, windows
exe_suffixconsts::EXE_SUFFIX.exe, .nexe
exe_extensionconsts::EXE_EXTENSIONexe
empty“”

val

The value feature needs to be enabled.

Use $val:name (e.g. $val: rand-16) to obtain the values. Unlike $const:, most of the values here are obtained at runtime.

nameexprexample
rand-[usize]$val: rand-1690aU0QqYnx1gPEgN
empty$val: empty“”

$val: rand-[usize] syntax requires the rand feature to be enabled.

rand is used to obtain random content, and currently only supports strings.

remix

syntaxexprexample
env * [env_name]env * HOMEC:\Users\m
const * [const]const * archx86_64
dir * [dir]dir * dlC:\Users\m\Downloads
proj * (project): [ident]proj * (com.xy.z): local-dataC:\Users\m\AppData\Local\xy\z\data
val * [val]val * rand-32VcNCQy5IevkuoQKm70arpRpAC5QGtF9D

example

["
    $const: empty ??
        env * home ?
        env * HOME
",
    "test"
]

env* can be used for fallback, but unlike $env:, it does not automatically convert lowercase letters to uppercase, and it does not automatically convert - to _.

  • env * home retrieves $home, not $HOME.
  • $env: home => $HOME
  • env * xdg-data-home => $xdg-data-home, not $XDG_DATA_HOME
  • $env: xdg-data-home => $XDG_DATA_HOME

Note: If the $env: expression contains a *, the automatic conversion feature will also be disabled.

The following syntax is currently supported:

  • $const: exe_suffix ? env * HOME ? env * XDG_DATA_HOME ? env * EXE_SUFFIX
  • $env: home ? xdg-data-home ? exe_suffix ? const * exe_suffix

Not supported:

  • $const: exe_suffix ? $env: home ? xdg-data-home ? exe_suffix

If it is supported, the parsing may become complicated and there could be confusion between $env: exe_suffix and $const: exe_suffix.

dirs

Here is an example of $dir for windows, for a full table, see Readme.

These are some base-dirs, or you could say standard directories. Use $dir:name (e.g. $dir:dl) or $dir:alias (e.g. $dir:download) to obtain the directory. Many of these contents are obtained from dirs, but there are also some additions.

namealiasWindows $dir
homeC:\Users\m
cache$localappdata:($home\AppData\Local)
cfgconfig$appdata: ($home\AppData\Roaming)
data$home\AppData\Roaming
local-datalocal_data$home\AppData\Local
local-cfglocal_config$home\AppData\Local
desktop$home\Desktop
docdocument$home\Documents
dldownload$home\Downloads
binexe$ms_dir\WindowsApps
first-pathfirst_path
last-pathlast_path
fonttypeface$ms_dir\Windows\Fonts
picpicture$home\Pictures
prefpreference$home\AppData\Roaming
pubpublic$home\Public
runtimeNone
stateNone
video$home\Videos
musicaudio$home\Music
template$ms_dir\Windows\Templates
tmp$tmpdir
tmp-randtmp_random$tmpdir\[random]
temptemporaryenv::temp_dir()
cli-datacli_data$home\AppData\Local
cli-cfgcli_config$home\AppData\Local
cli-cachecli_cache$home\AppData\Local
progam-filesprogram_files$ProgramFiles: (C:\Program Files)
program-files-x86program_files_x86$ProgramFiles(x86): (C:\Program Files (x86))
common-program-filescommon_program_files$CommonProgramFiles: (C:\Program Files\Common Files)
common-program-files-x86common_program_files_x86$CommonProgramFiles(x86): (C:\Program Files (x86)\Common Files)
program-dataprogram_data$ProgramData: (C:\ProgramData)
microsoft$home\AppData\Roaming\Microsoft
local-lowlocal_low$home\AppData\LocalLow
empty“”

Note: project_dirs has more advanced features. Here are some simple introductions.

For example, $proj(com. x. y): data will generate a data directory for this project (It does not create it automatically, just generates its value).

  • On Android, it is /data/data/com.x.y
  • On macOS, it is /Users/[username]/Library/Application Support/com.x.y

Modules

Macros

Structs

  • ProjectDirs computes the location of cache, config or data directories for a specific application, which are derived from the standard directories and the name of the project/organization.

Enums

Type Definitions

  • Type alias OsCow for handling OS Strings assigned to the heap or the stack.