#![allow(unused)]
use std::path::PathBuf;
pub const PYKE_ROOT: &str = "ort.pyke.io";
#[cfg(all(target_os = "windows", target_arch = "x86"))]
macro_rules! win32_extern {
($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
#[link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated")]
unsafe extern $abi {
$(#[$doc])?
$(#[link_name=$link_name])?
fn $($function)*;
}
)
}
#[cfg(all(target_os = "windows", not(target_arch = "x86")))]
macro_rules! win32_extern {
($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => (
#[link(name = $library, kind = "raw-dylib", modifiers = "+verbatim")]
unsafe extern "C" {
$(#[$doc])?
$(#[link_name=$link_name])?
fn $($function)*;
}
)
}
#[cfg(target_os = "windows")]
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
mod windows {
use std::{
ffi::{OsString, c_void},
os::windows::prelude::OsStringExt,
path::PathBuf,
ptr, slice
};
#[repr(C)]
#[derive(Clone, Copy)]
struct GUID {
data1: u32,
data2: u16,
data3: u16,
data4: [u8; 8]
}
impl GUID {
pub const fn from_u128(uuid: u128) -> Self {
Self {
data1: (uuid >> 96) as u32,
data2: ((uuid >> 80) & 0xffff) as u16,
data3: ((uuid >> 64) & 0xffff) as u16,
#[allow(clippy::cast_possible_truncation)]
data4: (uuid as u64).to_be_bytes()
}
}
}
type HRESULT = i32;
type PWSTR = *mut u16;
type PCWSTR = *const u16;
type HANDLE = isize;
type KNOWN_FOLDER_FLAG = i32;
win32_extern!("SHELL32.DLL" "system" fn SHGetKnownFolderPath(rfid: *const GUID, dwflags: KNOWN_FOLDER_FLAG, htoken: HANDLE, ppszpath: *mut PWSTR) -> HRESULT);
win32_extern!("KERNEL32.DLL" "system" fn lstrlenW(lpstring: PCWSTR) -> i32);
win32_extern!("OLE32.DLL" "system" fn CoTaskMemFree(pv: *const ::core::ffi::c_void) -> ());
fn known_folder(folder_id: GUID) -> Option<PathBuf> {
unsafe {
let mut path_ptr: PWSTR = ptr::null_mut();
let result = SHGetKnownFolderPath(&folder_id, 0, HANDLE::default(), &mut path_ptr);
if result == 0 {
let len = lstrlenW(path_ptr) as usize;
let path = slice::from_raw_parts(path_ptr, len);
let ostr: OsString = OsStringExt::from_wide(path);
CoTaskMemFree(path_ptr as *const c_void);
Some(PathBuf::from(ostr))
} else {
CoTaskMemFree(path_ptr as *const c_void);
None
}
}
}
#[allow(clippy::unusual_byte_groupings)]
const FOLDERID_LOCAL_APP_DATA: GUID = GUID::from_u128(0xf1b32785_6fba_4fcf_9d557b8e7f157091);
#[must_use]
pub fn known_folder_local_app_data() -> Option<PathBuf> {
known_folder(FOLDERID_LOCAL_APP_DATA)
}
}
#[cfg(target_os = "windows")]
#[must_use]
fn cache_dir_default() -> Option<PathBuf> {
self::windows::known_folder_local_app_data().map(|h| h.join(PYKE_ROOT))
}
#[cfg(unix)]
#[allow(non_camel_case_types)]
mod unix {
use std::{
env,
ffi::{CStr, OsString, c_char, c_int, c_long},
mem,
os::unix::prelude::OsStringExt,
path::PathBuf,
ptr
};
type uid_t = u32;
type gid_t = u32;
type size_t = usize;
#[repr(C)]
struct passwd {
pub pw_name: *mut c_char,
pub pw_passwd: *mut c_char,
pub pw_uid: uid_t,
pub pw_gid: gid_t,
pub pw_gecos: *mut c_char,
pub pw_dir: *mut c_char,
pub pw_shell: *mut c_char
}
unsafe extern "C" {
fn sysconf(name: c_int) -> c_long;
fn getpwuid_r(uid: uid_t, pwd: *mut passwd, buf: *mut c_char, buflen: size_t, result: *mut *mut passwd) -> c_int;
fn getuid() -> uid_t;
}
const SC_GETPW_R_SIZE_MAX: c_int = 70;
#[must_use]
pub fn is_absolute_path(path: OsString) -> Option<PathBuf> {
let path = PathBuf::from(path);
if path.is_absolute() { Some(path) } else { None }
}
#[cfg(not(target_os = "windows"))]
#[must_use]
pub fn home_dir() -> Option<PathBuf> {
return env::var_os("HOME")
.and_then(|h| if h.is_empty() { None } else { Some(h) })
.or_else(|| unsafe { fallback() })
.map(PathBuf::from);
#[cfg(any(target_os = "android", target_os = "ios", target_os = "emscripten"))]
unsafe fn fallback() -> Option<OsString> {
None
}
#[cfg(not(any(target_os = "android", target_os = "ios", target_os = "emscripten")))]
unsafe fn fallback() -> Option<OsString> {
let amt = match unsafe { sysconf(SC_GETPW_R_SIZE_MAX) } {
n if n < 0 => 512,
n => n as usize
};
let mut buf = Vec::with_capacity(amt);
let mut passwd: passwd = unsafe { mem::zeroed() };
let mut result = ptr::null_mut();
match unsafe { getpwuid_r(getuid(), &mut passwd, buf.as_mut_ptr(), buf.capacity(), &mut result) } {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = unsafe { CStr::from_ptr(ptr) }.to_bytes();
if bytes.is_empty() { None } else { Some(OsStringExt::from_vec(bytes.to_vec())) }
}
_ => None
}
}
}
}
#[cfg(target_os = "linux")]
#[must_use]
fn cache_dir_default() -> Option<PathBuf> {
std::env::var_os("XDG_CACHE_HOME")
.and_then(self::unix::is_absolute_path)
.or_else(|| self::unix::home_dir().map(|h| h.join(".cache").join(PYKE_ROOT)))
}
#[cfg(target_os = "macos")]
#[must_use]
fn cache_dir_default() -> Option<PathBuf> {
self::unix::home_dir().map(|h| h.join("Library/Caches").join(PYKE_ROOT))
}
#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
fn cache_dir_default() -> Option<PathBuf> {
None
}
pub fn cache_dir() -> Option<PathBuf> {
#[cfg(miri)]
return Some(PathBuf::from("."));
std::env::var_os("ORT_CACHE_DIR").map(PathBuf::from).or_else(cache_dir_default)
}