simple-fs 0.12.1

Simple and convenient API for File System access
Documentation
# simple-fs – Public APIs (by category)

Note: Root crate re-exports most modules, so items are accessible from the crate root unless noted.

```toml
simple-fs = "0.12.0-beta.1"
# or with features
simple-fs = {version = "0.12.0-beta.1", features = ["with-json", "with-toml", "bin-nums"]}
# or `features = ["full"]
```

## Core

- Type alias: `Result<T> = core::result::Result<T, Error>`

- Error type: `Error`


## Paths (SPath)

- Type: `SPath` (UTF-8, normalized posix-style path, `/` separators)

- Constructors
  - `SPath::new(path: impl Into<Utf8PathBuf>) -> SPath` (always normalizes)
    - since: `0.12.0`
  
  - `SPath::from_std_path_buf(path_buf: PathBuf) -> Result<SPath>`
  
  - `SPath::from_std_path(path: impl AsRef<Path>) -> Result<SPath>`
  
  - `SPath::from_fs_entry(fs_entry: fs::DirEntry) -> Result<SPath>`
    - since: `0.12.0`
  
  - `SPath::from_walkdir_entry(wd_entry: walkdir::DirEntry) -> Result<SPath>`
  
  - `SPath::from_std_path_ok(path: impl AsRef<Path>) -> Option<SPath>`
  
  - `SPath::from_std_path_buf_ok(path_buf: PathBuf) -> Option<SPath>`
  
  - `SPath::from_fs_entry_ok(fs_entry: fs::DirEntry) -> Option<SPath>`
  
  - `SPath::from_walkdir_entry_ok(wd_entry: walkdir::DirEntry) -> Option<SPath>`

- Conversions (consuming / views)
  - `SPath::into_std_path_buf(self) -> PathBuf`
  
  - `SPath::std_path(&self) -> &Path`
  
  - `SPath::path(&self) -> &Utf8Path`
  
  - `SPath::as_std_path(&self) -> &Path`

- Getters
  - `SPath::to_str(&self) -> &str` (deprecated)
  
  - `SPath::as_str(&self) -> &str`
  
  - `SPath::file_name(&self) -> Option<&str>`
  
  - `SPath::name(&self) -> &str`
  
  - `SPath::parent_name(&self) -> &str`
  
  - `SPath::file_stem(&self) -> Option<&str>`
  
  - `SPath::stem(&self) -> &str`
  
  - `SPath::extension(&self) -> Option<&str>`
  
  - `SPath::ext(&self) -> &str`
  
  - `SPath::is_dir(&self) -> bool`
  
  - `SPath::is_file(&self) -> bool`
  
  - `SPath::exists(&self) -> bool`
  
  - `SPath::is_absolute(&self) -> bool`
  
  - `SPath::is_relative(&self) -> bool`

  - `SPath::mime_type(&self) -> Option<&'static str>`

  - `SPath::is_likely_text(&self) -> bool`

- Metadata
  - `SPath::meta(&self) -> Result<SMeta>`
  
  - `SPath::metadata(&self) -> Result<Metadata>`

- Transformers
  - `SPath::canonicalize(&self) -> Result<SPath>`
  
  - `SPath::collapse(&self) -> SPath`
  
  - `SPath::into_collapsed(self) -> SPath`
  
  - `SPath::is_collapsed(&self) -> bool`

- Parent & Join
  - `SPath::parent(&self) -> Option<SPath>`
  
  - `SPath::append_suffix(&self, suffix: &str) -> SPath`
  
  - `SPath::join(&self, leaf_path: impl Into<Utf8PathBuf>) -> SPath`
  
  - `SPath::join_std_path(&self, leaf_path: impl AsRef<Path>) -> Result<SPath>`
  
  - `SPath::new_sibling(&self, leaf_path: impl AsRef<str>) -> SPath`
  
  - `SPath::new_sibling_std_path(&self, leaf_path: impl AsRef<Path>) -> Result<SPath>`

- Diff
  - `SPath::diff(&self, base: impl AsRef<Utf8Path>) -> Option<SPath>`
  
  - `SPath::try_diff(&self, base: impl AsRef<Utf8Path>) -> Result<SPath>`

- Replace
  - `SPath::replace_prefix(&self, base: impl AsRef<str>, with: impl AsRef<str>) -> SPath`
  
  - `SPath::into_replace_prefix(self, base: impl AsRef<str>, with: impl AsRef<str>) -> SPath`

- Extensions
  - `SPath::into_ensure_extension(self, ext: &str) -> SPath`
  
  - `SPath::ensure_extension(&self, ext: &str) -> SPath`
  
  - `SPath::append_extension(&self, ext: &str) -> SPath`

- Other
  - `SPath::strip_prefix(&self, prefix: impl AsRef<str>) -> Result<SPath>`
    - since: `0.12.0` (API changed from `AsRef<Path>`)
  
  - `SPath::starts_with(&self, base: impl AsRef<Path>) -> bool`
  
  - `SPath::dir_before_glob(&self) -> Option<SPath>`

- Traits (summary)
  - Display
  
  - AsRef<SPath> / AsRef<Path> / AsRef<Utf8Path> / AsRef<str>
  
  - From<Utf8PathBuf> / From<&Utf8Path> / From<String> / From<&String> / From<&str>
  
  - From<SPath> for String / PathBuf / Utf8PathBuf
  
  - From<&SPath> for String / PathBuf
  
  - TryFrom<PathBuf> / TryFrom<fs::DirEntry> / TryFrom<walkdir::DirEntry>

## File I/O

- `create_file(file_path: impl AsRef<Path>) -> Result<File>`

- `read_to_string(file_path: impl AsRef<Path>) -> Result<String>`

- `open_file(path: impl AsRef<Path>) -> Result<File>`

- `get_buf_reader(file: impl AsRef<Path>) -> Result<BufReader<File>>`

- `get_buf_writer(file_path: impl AsRef<Path>) -> Result<BufWriter<File>>`


## Spans

- `read_span(path: impl AsRef<SPath>, start: usize, end: usize) -> Result<String>`

- `line_spans(path: impl AsRef<SPath>) -> Result<Vec<(usize, usize)>>`

- `csv_row_spans(path: impl AsRef<SPath>) -> Result<Vec<(usize, usize)>>`


## Directories

- `ensure_dir(dir: impl AsRef<Path>) -> Result<bool>`

- `ensure_file_dir(file_path: impl AsRef<Path>) -> Result<bool>`


## Listing & Globbing

- Directory iteration
  - `iter_dirs(dir: impl AsRef<Path>, include_globs: Option<&[&str]>, list_options: Option<ListOptions<'_>>) -> Result<impl Iterator<Item = SPath>>`
  
  - `list_dirs(dir: impl AsRef<Path>, include_globs: Option<&[&str]>, list_options: Option<ListOptions<'_>>) -> Result<Vec<SPath>>`

- File iteration
  - `iter_files(dir: impl AsRef<Path>, include_globs: Option<&[&str]>, list_options: Option<ListOptions<'_>>) -> Result<GlobsFileIter>`
  
  - `list_files(dir: impl AsRef<Path>, include_globs: Option<&[&str]>, list_options: Option<ListOptions<'_>>) -> Result<Vec<SPath>>`
  
  - Type: `GlobsFileIter` (Iterator<Item = SPath>)

- Options
  - `ListOptions<'a> { exclude_globs: Option<Vec<&'a str>>, relative_glob: bool, depth: Option<usize> }`
  - Defaults: `relative_glob: false`, `exclude_globs: None` (but `iter_files` applies `DEFAULT_EXCLUDE_GLOBS` if `None`)
  
  - `ListOptions::new(globs: Option<&'a [&'a str]>) -> ListOptions<'a>`
  
  - `ListOptions::from_relative_glob(val: bool) -> ListOptions<'a>`
  
  - `ListOptions::with_exclude_globs(self, globs: &'a [&'a str]) -> Self`
  
  - `ListOptions::with_relative_glob(self) -> Self`
  
  - `ListOptions::exclude_globs(&'a self) -> Option<&'a [&'a str]>`
  
  - From conversions: `From<&'a [&'a str]>`, `From<Option<&'a [&'a str]>>`, `From<Vec<&'a str>>`

- Glob utilities
  - `DEFAULT_EXCLUDE_GLOBS: &[&str]`
  
  - `get_glob_set(globs: &[&str]) -> Result<globset::GlobSet>`
    - Note: The returned `globset::GlobSet` (from `globset` crate) can be used to check if an `SPath` matches: `glob_set.is_match(spath)`.
  
  - `longest_base_path_wild_free(pattern: &SPath) -> SPath`
  
  - `get_depth(patterns: &[&str], depth: Option<usize>) -> usize`

- Sorting
  - `sort_by_globs<T>(items: Vec<T>, globs: &[&str], options: impl Into<SortByGlobsOptions>) -> Result<Vec<T>> where T: AsRef<SPath>` (Sorts by glob priority index, then by full path. Non-matches preserved in original order. Default `no_match_position: End`.)

  - `struct SortByGlobsOptions { end_weighted: bool, no_match_position: NoMatchPosition }`

  - `enum NoMatchPosition { Start, End }`


## Reshape / Normalize

- Normalizer
  - `needs_normalize(path: &Utf8Path) -> bool`
  
  - `into_normalized(path: Utf8PathBuf) -> Utf8PathBuf`
    - Note: Handles separator normalization and redundant `./` cleanup, this does not collapse `..`.

- Collapser
  - `into_collapsed(path: impl Into<Utf8PathBuf>) -> Utf8PathBuf`
  
  - `try_into_collapsed(path: impl Into<Utf8PathBuf>) -> Option<Utf8PathBuf>`
  
  - `is_collapsed(path: impl AsRef<Utf8Path>) -> bool`
  - Note: Collapsing `..` is explicit through collapser APIs, `SPath::new` does not implicitly collapse `..`.


## Safer Remove

- Function: `safer_remove_dir(dir_path: &SPath, options: impl Into<SaferRemoveOptions<'a>>) -> Result<bool>`
- Function: `safer_remove_file(file_path: &SPath, options: impl Into<SaferRemoveOptions<'a>>) -> Result<bool>`
- Note: `options` cannot be `None`. Use `SaferRemoveOptions::default()` or `()` for default safety.

- Type: `SaferRemoveOptions<'a>`
  - `SaferRemoveOptions::default()`: `restrict_to_current_dir: true` (path must be below CWD), others `None`.
  - `SaferRemoveOptions::with_must_contain_any(self, patterns: &'a [&'a str]) -> Self`
  - `SaferRemoveOptions::with_must_contain_all(self, patterns: &'a [&'a str]) -> Self`
  - `SaferRemoveOptions::with_restrict_to_current_dir(self, val: bool) -> Self`


## Safer Trash

- Function: `safer_trash_dir(dir_path: &SPath, options: impl Into<SaferTrashOptions<'a>>) -> Result<bool>`

- Function: `safer_trash_file(file_path: &SPath, options: impl Into<SaferTrashOptions<'a>>) -> Result<bool>`

- Note: `options` cannot be `None`. Use `SaferTrashOptions::default()` or `()` for default safety.

- Type: `SaferTrashOptions<'a>`
  - `SaferTrashOptions::default()`: `restrict_to_current_dir: true` (path must be below CWD), others `None`.
  - `SaferTrashOptions::with_must_contain_any(self, patterns: &'a [&'a str]) -> Self`
  - `SaferTrashOptions::with_must_contain_all(self, patterns: &'a [&'a str]) -> Self`
  - `SaferTrashOptions::with_restrict_to_current_dir(self, val: bool) -> Self`


## Common

- `home_dir() -> Result<SPath>`

- `current_dir() -> Result<SPath>`

- Pretty size (Fixed width 9 chars, right aligned number, unit aligned)
  - `struct PrettySizeOptions { lowest_unit: SizeUnit }`
  
  - `enum SizeUnit { B, KB, MB, GB, TB }`
  
  - `SizeUnit::new(val: &str) -> SizeUnit`
  
  - `pretty_size(size_in_bytes: u64) -> String`
  
  - `pretty_size_with_options(size_in_bytes: u64, options: impl Into<PrettySizeOptions>) -> String`

- File metadata
  - `struct SMeta { created_epoch_us: i64, modified_epoch_us: i64, size: u64, is_file: bool, is_dir: bool }`


## Watch

- `watch(path: impl AsRef<Path>) -> Result<SWatcher>` (Debounced: ~200ms)

- `struct SWatcher { rx: flume::Receiver<Vec<SEvent>>, /* keeps internal debouncer alive */ }`

- `struct SEvent { spath: SPath, skind: SEventKind }`

- `enum SEventKind { Create, Modify, Remove, Other }`

- Re-export: `DebouncedEvent` (from `notify_debouncer_full`)


## Feature-gated: with-json

- Load
  - `load_json<T: serde::de::DeserializeOwned>(file: impl AsRef<Path>) -> Result<T>`
  
  - `load_ndjson(file: impl AsRef<Path>) -> Result<Vec<serde_json::Value>>`
  
  - `stream_ndjson(file: impl AsRef<Path>) -> Result<impl Iterator<Item = Result<serde_json::Value>>>`

- Parse (NDJSON)
  - `parse_ndjson_iter(input: &str) -> impl Iterator<Item = Result<serde_json::Value>>`
  
  - `parse_ndjson(input: &str) -> Result<Vec<serde_json::Value>>`
  
  - `parse_ndjson_from_reader<R: std::io::BufRead>(reader: R) -> Result<Vec<serde_json::Value>>`
  
  - `parse_ndjson_iter_from_reader<R: std::io::BufRead>(reader: R) -> impl Iterator<Item = Result<serde_json::Value>>`

- Save
  - `save_json<T: serde::Serialize>(file: impl AsRef<Path>, data: &T) -> Result<()>`
  
  - `save_json_pretty<T: serde::Serialize>(file: impl AsRef<Path>, data: &T) -> Result<()>`
  
  - `append_json_line<T: serde::Serialize>(file: impl AsRef<Path>, value: &T) -> Result<()>`
  
  - `append_json_lines<'a, T: serde::Serialize + 'a, I: IntoIterator<Item = &'a T>>(file: impl AsRef<Path>, values: I) -> Result<()>`


## Feature-gated: with-toml

- `load_toml<T: serde::de::DeserializeOwned>(file_path: impl AsRef<Path>) -> Result<T>`

- `save_toml<T: serde::Serialize>(file_path: impl AsRef<Path>, data: &T) -> Result<()>`


## Feature-gated: bin-nums

- Load (binary)
  - `load_be_f64(file) -> Result<Vec<f64>>`, `load_le_f64(file) -> Result<Vec<f64>>`
  
  - `load_be_f32(file) -> Result<Vec<f32>>`, `load_le_f32(file) -> Result<Vec<f32>>`
  
  - `load_be_u64(file) -> Result<Vec<u64>>`, `load_le_u64(file) -> Result<Vec<u64>>`
  
  - `load_be_u32(file) -> Result<Vec<u32>>`, `load_le_u32(file) -> Result<Vec<u32>>`
  
  - `load_be_u16(file) -> Result<Vec<u16>>`, `load_le_u16(file) -> Result<Vec<u16>>`
  
  - `load_be_i64(file) -> Result<Vec<i64>>`, `load_le_i64(file) -> Result<Vec<i64>>`
  
  - `load_be_i32(file) -> Result<Vec<i32>>`, `load_le_i32(file) -> Result<Vec<i32>>`
  
  - `load_be_i16(file) -> Result<Vec<i16>>`, `load_le_i16(file) -> Result<Vec<i16>>`

- Save (binary)
  - `save_be_f64(file, data: &[f64]) -> Result<()>`, `save_le_f64(file, data: &[f64]) -> Result<()>`
  
  - `save_be_f32(file, data: &[f32]) -> Result<()>`, `save_le_f32(file, data: &[f32]) -> Result<()>`
  
  - `save_be_u64(file, data: &[u64]) -> Result<()>`, `save_le_u64(file, data: &[u64]) -> Result<()>`
  
  - `save_be_u32(file, data: &[u32]) -> Result<()>`, `save_le_u32(file, data: &[u32]) -> Result<()>`
  
  - `save_be_u16(file, data: &[u16]) -> Result<()>`, `save_le_u16(file, data: &[u16]) -> Result<()>`
  
  - `save_be_i64(file, data: &[i64]) -> Result<()>`, `save_le_i64(file, data: &[i64]) -> Result<()>`
  
  - `save_be_i32(file, data: &[i32]) -> Result<()>`, `save_le_i32(file, data: &[i32]) -> Result<()>`
  
  - `save_be_i16(file, data: &[i16]) -> Result<()>`, `save_le_i16(file, data: &[i16]) -> Result()`