reactive_graph_plugin_service_impl/
plugin_paths.rs

1use std::env::consts::DLL_EXTENSION;
2use std::ffi::OsStr;
3use std::path::Path;
4use std::path::PathBuf;
5use std::time::SystemTime;
6use std::time::UNIX_EPOCH;
7
8fn get_timestamp() -> u64 {
9    SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs()
10}
11
12// TODO: replace relative with absolute path replacement
13pub fn get_deploy_path(path: &Path) -> Option<PathBuf> {
14    file_prefix(path).and_then(|file_prefix| {
15        path.parent()
16            .and_then(|path| path.parent())
17            .map(|path| path.join("deploy").join(file_prefix).with_extension(DLL_EXTENSION))
18    })
19}
20
21// TODO: replace relative with absolute path replacement
22pub fn get_install_path(path: &Path) -> Option<PathBuf> {
23    file_prefix(path).and_then(|file_prefix| {
24        path.parent().and_then(|path| path.parent()).map(|path| {
25            path.join("installed")
26                .join(file_prefix)
27                .with_extension(format!("{}.{}", get_timestamp(), DLL_EXTENSION))
28        })
29    })
30}
31
32pub fn get_stem(path: &Path) -> Option<String> {
33    file_prefix(path).and_then(|stem| Some(stem.to_str()?.to_string()))
34}
35
36// Use this workaround until #![feature(path_file_prefix)] is stabilized
37pub fn file_prefix(path: &Path) -> Option<&OsStr> {
38    path.file_name().map(split_file_at_dot).map(|(before, _after)| before)
39}
40
41// Use this workaround until #![feature(path_file_prefix)] is stabilized
42fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
43    let slice = os_str_as_u8_slice(file);
44    if slice == b".." {
45        return (file, None);
46    }
47
48    // The unsafety here stems from converting between &OsStr and &[u8]
49    // and back. This is safe to do because (1) we only look at ASCII
50    // contents of the encoding and (2) new &OsStr values are produced
51    // only from ASCII-bounded slices of existing &OsStr values.
52    let i = match slice[1..].iter().position(|b| *b == b'.') {
53        Some(i) => i + 1,
54        None => return (file, None),
55    };
56    let before = &slice[..i];
57    let after = &slice[i + 1..];
58    unsafe { (u8_slice_as_os_str(before), Some(u8_slice_as_os_str(after))) }
59}
60
61// Use this workaround until #![feature(path_file_prefix)] is stabilized
62fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
63    unsafe { &*(s as *const OsStr as *const [u8]) }
64}
65
66// Use this workaround until #![feature(path_file_prefix)] is stabilized
67unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
68    // SAFETY: see the comment of `os_str_as_u8_slice`
69    unsafe { &*(s as *const [u8] as *const OsStr) }
70}