1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#![feature(specialization, integer_atomics, box_syntax)]

#[macro_use]
extern crate kg_diag_derive;
#[macro_use]
extern crate kg_display_derive;
#[macro_use]
extern crate serde_derive;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use heapsize::HeapSizeOf;
use kg_diag::io::fs;
use kg_diag::*;
use kg_symbol::Symbol;
use kg_utils::collections::LinkedHashMap;

pub use tree::convert::Primitive;
use tree::metadata::Metadata;
pub use tree::metadata::{FileFormat, FileInfo};
pub use tree::node::{Kind, KindMask, Node, Value};
pub use tree::{NodeRef, TreeErrorDetail};

mod tree;

pub type Properties = LinkedHashMap<Symbol, NodeRef>;
pub type Elements = Vec<NodeRef>;

pub mod diff;
pub mod opath;

pub mod serial;

thread_local! {
    static BASE_PATH: RefCell<PathBuf> = RefCell::new(std::env::current_dir().unwrap());
    static BASE_PATH_STACK: RefCell<Vec<PathBuf>> = RefCell::new(Vec::new());
}

pub fn set_base_path<P: AsRef<Path> + Into<PathBuf>>(base_path: P) {
    debug_assert!(base_path.as_ref().is_absolute());
    BASE_PATH_STACK.with(|s| s.borrow_mut().clear());
    BASE_PATH.with(|b| b.replace(base_path.into()));
}

pub fn push_base_path<P: AsRef<Path> + Into<PathBuf>>(base_path: P) {
    debug_assert!(base_path.as_ref().is_absolute());
    let current_path = BASE_PATH.with(|b| b.replace(base_path.into()));
    BASE_PATH_STACK.with(|s| s.borrow_mut().push(current_path));
}

pub fn pop_base_path() -> PathBuf {
    let path = BASE_PATH_STACK.with(|s| {
        s.borrow_mut()
            .pop()
            .expect("kg_tree::pop_base_path() called on an empty stack")
    });
    BASE_PATH.with(|b| b.replace(path))
}

pub fn relative_path(path: &Path) -> &Path {
    debug_assert!(path.is_absolute());
    BASE_PATH.with(|b| unsafe {
        std::mem::transmute(path.strip_prefix(b.borrow().as_path()).unwrap_or(path))
    })
}

pub fn resolve_path(path: &Path) -> Cow<Path> {
    if path.is_absolute() {
        path.into()
    } else {
        BASE_PATH.with(|b| b.borrow().as_path().join(path).into())
    }
}

pub fn resolve_path_str(path: &str) -> Cow<Path> {
    resolve_path(Path::new(path))
}

struct PathBufHeapSize<'a>(&'a PathBuf);

impl<'a> HeapSizeOf for PathBufHeapSize<'a> {
    fn heap_size_of_children(&self) -> usize {
        unsafe { std::mem::transmute::<&PathBuf, &Vec<u8>>(self.0).heap_size_of_children() }
    }
}

pub type NodeMap = HashMap<*const Node, NodeRef>;

pub trait Remappable {
    fn remap(&mut self, node_map: &NodeMap);
}