Skip to main content

DataStorage

Struct DataStorage 

Source
pub struct DataStorage { /* private fields */ }
Expand description

Cross-platform data storage path manager.

The DataStorage struct provides a centralized way to manage file paths for application data across different operating systems. It encapsulates platform-specific logic and provides a consistent interface for path resolution and directory management.

§Design Philosophy

The storage manager follows these principles:

  • Platform Compliance: Adheres to OS-specific directory conventions
  • User-Centric: Stores data in user-accessible locations
  • Predictable: Provides consistent behavior across platforms
  • Robust: Handles edge cases and permission issues gracefully

§Initialization

The base path is determined during construction based on:

  1. Operating system detection
  2. Environment variable resolution
  3. Fallback to safe defaults if needed
  4. Organization and application name incorporation

§Thread Safety

The struct is designed to be used safely across multiple threads, as path resolution is deterministic and doesn’t modify internal state.

Implementations§

Source§

impl DataStorage

Source

pub fn new() -> Self

Creates a new DataStorage instance with platform-appropriate base path.

This constructor performs automatic platform detection and constructs the appropriate base directory path following OS conventions. It uses environment variables where available and falls back to safe defaults.

§Platform Resolution Logic

The constructor determines the base path using this priority order:

  1. Environment Variables: Uses OS-specific environment variables
  2. Fallback Values: Uses current directory if environment vars fail
  3. Path Construction: Appends organization and application names
  4. Validation: Ensures the resulting path is usable
§Application Metadata Integration

The method uses compile-time metadata to construct paths:

  • APP_METADATA_OWNER: Organization name (e.g., “lacodda”)
  • APP_METADATA_NAME: Application name (e.g., “kasl”)

This ensures consistent branding and path structure across builds.

§Returns

Returns a new DataStorage instance configured for the current platform and user environment.

§Example
use kasl::libs::data_storage::DataStorage;

// Create platform-specific storage manager
let storage = DataStorage::new();

// Base path is automatically configured; resolve a file within it
let db_path = storage.get_path("kasl.db")?;
println!("Database path: {:?}", db_path);
§Environment Variable Usage
  • Windows: Uses LOCALAPPDATA for local application data
  • macOS: Uses HOME to construct ~/Library/Application Support path
  • Linux: Uses HOME to construct ~/.local/share path
§Error Resilience

If environment variables are not available, the constructor:

  • Falls back to current directory (“.”)
  • Continues with path construction
  • Defers directory creation until first access
  • Allows application to function in restricted environments
Source

pub fn get_path(&self, file_name: &str) -> Result<PathBuf>

Resolves a filename to a complete path within the application data directory.

This method takes a filename and returns the complete path where that file should be stored within the application’s data directory. It automatically handles directory creation and ensures the path is ready for file operations.

§Directory Creation

The method ensures that all necessary parent directories exist:

  • Creates the entire directory tree if missing
  • Uses OS-appropriate permissions for new directories
  • Handles concurrent access scenarios safely
  • Provides clear error messages if creation fails
§Path Construction

The resulting path combines:

  1. Base Path: Platform-specific application data directory
  2. Organization: Namespace isolation (e.g., “lacodda”)
  3. Application: Application-specific subdirectory (e.g., “kasl”)
  4. Filename: The requested file within the application directory
§Arguments
  • file_name - Name of the file to resolve to a full path
§Returns

Returns the complete PathBuf where the file should be stored, or an error if directory creation fails or paths are invalid.

§Example
use kasl::libs::data_storage::DataStorage;

let storage = DataStorage::new();

// Get path for database file
let db_path = storage.get_path("kasl.db")?;
// Result: /home/user/.local/share/lacodda/kasl/kasl.db (Linux)
//         C:\Users\User\AppData\Local\lacodda\kasl\kasl.db (Windows)

// Get path for configuration file
let config_path = storage.get_path("config.json")?;

// Get path for session cache
let session_path = storage.get_path(".jira_session_id")?;
§File Naming Conventions

The method accepts any valid filename, but common patterns include:

  • Database files: kasl.db, backup.db
  • Configuration: config.json, settings.toml
  • Cache files: .session_id, .auth_token
  • Process files: kasl-watch.pid
  • Logs: kasl.log, debug.log
§Error Scenarios

The method can fail in several situations:

  • Permission Denied: Insufficient permissions to create directories
  • Disk Full: No space available for directory creation
  • Path Too Long: Resulting path exceeds OS limits
  • Invalid Characters: Filename contains invalid characters for the OS
  • Read-Only Filesystem: Target location is mounted read-only
§Concurrency Safety

The directory creation process is designed to handle concurrent access:

  • Multiple processes can safely call this method simultaneously
  • Directory creation is atomic where supported by the OS
  • Existing directories are not affected by creation attempts
  • Race conditions in directory creation are handled gracefully

Trait Implementations§

Source§

impl Clone for DataStorage

Source§

fn clone(&self) -> DataStorage

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for DataStorage

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for DataStorage

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more