1use crate::{sys, SBStream};
8use std::ffi::CStr;
9use std::fmt;
10use std::path::Path;
11
12pub struct SBFileSpec {
18    pub raw: sys::SBFileSpecRef,
20}
21
22impl SBFileSpec {
23    pub(crate) fn wrap(raw: sys::SBFileSpecRef) -> SBFileSpec {
25        SBFileSpec { raw }
26    }
27
28    pub(crate) fn maybe_wrap(raw: sys::SBFileSpecRef) -> Option<SBFileSpec> {
30        if unsafe { sys::SBFileSpecIsValid(raw) } {
31            Some(SBFileSpec { raw })
32        } else {
33            None
34        }
35    }
36
37    pub fn from_path<P: AsRef<Path>>(path: P, resolve: bool) -> Self {
39        let path_cstring =
40            std::ffi::CString::new(path.as_ref().as_os_str().as_encoded_bytes()).unwrap();
41        Self::wrap(unsafe { sys::CreateSBFileSpec3(path_cstring.as_ptr(), resolve) })
42    }
43
44    pub fn is_valid(&self) -> bool {
46        unsafe { sys::SBFileSpecIsValid(self.raw) }
47    }
48
49    pub fn exists(&self) -> bool {
51        unsafe { sys::SBFileSpecExists(self.raw) }
52    }
53
54    pub fn filename(&self) -> &str {
56        unsafe {
57            match CStr::from_ptr(sys::SBFileSpecGetFilename(self.raw)).to_str() {
58                Ok(s) => s,
59                _ => panic!("Invalid string?"),
60            }
61        }
62    }
63
64    pub fn directory(&self) -> &str {
66        unsafe {
67            match CStr::from_ptr(sys::SBFileSpecGetDirectory(self.raw)).to_str() {
68                Ok(s) => s,
69                _ => panic!("Invalid string?"),
70            }
71        }
72    }
73}
74
75impl Clone for SBFileSpec {
76    fn clone(&self) -> SBFileSpec {
77        SBFileSpec {
78            raw: unsafe { sys::CloneSBFileSpec(self.raw) },
79        }
80    }
81}
82
83impl fmt::Debug for SBFileSpec {
84    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
85        let stream = SBStream::new();
86        unsafe { sys::SBFileSpecGetDescription(self.raw, stream.raw) };
87        write!(fmt, "SBFileSpec {{ {} }}", stream.data())
88    }
89}
90
91impl Drop for SBFileSpec {
92    fn drop(&mut self) {
93        unsafe { sys::DisposeSBFileSpec(self.raw) };
94    }
95}
96
97unsafe impl Send for SBFileSpec {}
98unsafe impl Sync for SBFileSpec {}
99
100#[cfg(feature = "graphql")]
101#[juniper::graphql_object]
102impl SBFileSpec {
103    fn exists() -> bool {
104        self.exists()
105    }
106
107    fn filename() -> &str {
108        self.filename()
109    }
110
111    fn directory() -> &str {
112        self.directory()
113    }
114}