deviceid 0.0.3

This package is used to help generate a unique random UUID as a deviceId.
Documentation
#![cfg(target_family = "unix")]

use crate::{DevDeviceId, Result};

const DEV_DEVICEID_PATH: &str = "Microsoft/DeveloperTools";
const FILENAME: &str = "deviceid";

#[cfg(target_os = "macos")]
fn root_path() -> Result<std::path::PathBuf> {
    const BASE_STORAGE_PATH: &str = "Library/Application Support";
    let home = std::env::var_os("HOME");
    match home {
        Some(home) => {
            let mut path = std::path::PathBuf::from(home);
            path.push(BASE_STORAGE_PATH);
            Ok(path)
        }
        None => Err(super::Error::StorageError(
            "HOME environment variable not set".to_string(),
        )),
    }
}

#[cfg(target_os = "linux")]
fn root_path() -> Result<std::path::PathBuf> {
    std::env::var_os("XDG_CACHE_HOME")
        .map(std::path::PathBuf::from)
        .or_else(|| {
            std::env::var_os("HOME").map(|home| {
                let mut path = std::path::PathBuf::from(home);
                path.push(".cache");
                path
            })
        })
        .ok_or_else(|| {
            super::Error::StorageError(
                "XDG_CACHE_HOME and HOME environment variables not set".to_string(),
            )
        })
}

fn folder_path() -> Result<std::path::PathBuf> {
    let mut path = root_path()?;
    path.push(DEV_DEVICEID_PATH);
    Ok(path)
}

fn path() -> Result<std::path::PathBuf> {
    let mut path = folder_path()?;
    path.push(FILENAME);
    Ok(path)
}

pub fn retrieve() -> Result<Option<DevDeviceId>> {
    let path = path()?;
    if path.exists() {
        // TODO: don't read too much!
        let data = std::fs::read(path).map_err(|e| super::Error::StorageError(e.to_string()))?;
        let id = uuid::Uuid::try_parse_ascii(data.as_slice())
            .map_err(|e| super::Error::BadUuidFormat(e.to_string()))?;
        Ok(Some(DevDeviceId(id)))
    } else {
        Ok(None)
    }
}

pub fn store(id: &DevDeviceId) -> Result<()> {
    std::fs::create_dir_all(folder_path()?)
        .map_err(|e| super::Error::StorageError(e.to_string()))?;
    if !path()?.exists() {
        let id_str = format!("{id}");
        std::fs::write(path()?, id_str.as_bytes())
            .map_err(|e| super::Error::StorageError(e.to_string()))?;
        Ok(())
    } else {
        Err(super::Error::AlreadySet)
    }
}