1use std::path::{Path, PathBuf};
2
3use widestring::U16CStr;
4use windows::{Win32::UI::Shell::IShellItem, core::Result};
5
6use crate::{ShellItem, ShellItemDisplayName, id_list::AbsoluteIDList};
7
8#[derive(Clone)]
10pub enum ShellPath<'a> {
11 Path(PathBuf),
12 IdList(&'a AbsoluteIDList),
14}
15
16impl From<PathBuf> for ShellPath<'static> {
17 fn from(value: PathBuf) -> Self {
18 Self::Path(value)
19 }
20}
21
22impl From<&Path> for ShellPath<'static> {
23 fn from(value: &Path) -> Self {
24 Self::Path(value.into())
25 }
26}
27
28impl<'a> ShellPath<'a> {
29 pub fn from_path_or_id_list(path: *const u16, id_list: &'a AbsoluteIDList) -> Option<Self> {
30 match (path.is_null(), id_list.0.is_null()) {
31 (true, true) => None,
32 (false, _) => {
34 let file = unsafe { U16CStr::from_ptr_str(path) };
35
36 Self::Path(file.to_os_string().into()).into()
37 }
38 (true, false) => Self::IdList(id_list).into(),
39 }
40 }
41
42 pub fn to_file_path(&self) -> Result<PathBuf> {
43 Ok(match self {
44 ShellPath::Path(path) => path.clone(),
45 ShellPath::IdList(id_list) => {
46 let item = IShellItem::from_id_list(id_list)?;
47 let name = item.get_display_name(ShellItemDisplayName::FileSystemPath)?;
48 name.to_os_string().into()
49 }
50 })
51 }
52}
53
54impl<'a> std::fmt::Debug for ShellPath<'a> {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 match self {
57 Self::Path(arg0) => f.debug_tuple("Path").field(arg0).finish(),
58 Self::IdList(arg0) => {
59 let mut f = f.debug_tuple("IdList");
60 let f = f.field(arg0);
61 if let Ok(path) = self.to_file_path() {
62 f.field(&path);
63 }
64 f.finish()
65 }
66 }
67 }
68}