netcorehost/hostfxr/
library.rs1use crate::{
2 dlopen2::wrapper::Container,
3 error::{HostingError, HostingResult},
4 pdcstring::PdCString,
5};
6use derive_more::From;
7use std::{
8 env::consts::EXE_SUFFIX,
9 ffi::OsString,
10 path::{Path, PathBuf},
11 sync::Arc,
12};
13
14pub(crate) type HostfxrLibrary = Container<crate::bindings::hostfxr::wrapper_option::Hostfxr>;
15pub(crate) type SharedHostfxrLibrary = Arc<HostfxrLibrary>;
16#[allow(unused, clippy::cast_possible_wrap)]
17pub(crate) const UNSUPPORTED_HOST_VERSION_ERROR_CODE: i32 =
18 HostingError::HostApiUnsupportedVersion.value() as i32;
19
20#[derive(Clone, From)]
22pub struct Hostfxr {
23 pub lib: SharedHostfxrLibrary,
25 pub(crate) dotnet_exe: PdCString,
26}
27
28fn find_dotnet_bin(hostfxr_path: impl AsRef<Path>) -> PathBuf {
29 let mut p = hostfxr_path.as_ref().to_path_buf();
30 loop {
31 if let Some(dir) = p.file_name() {
32 if dir == "dotnet" || dir == ".dotnet" {
33 break;
34 }
35 p.pop();
36 } else {
37 p.clear();
38 break;
39 }
40 }
41 p.push("dotnet");
42 let mut p = OsString::from(p);
43 p.extend(Path::new(EXE_SUFFIX));
44 PathBuf::from(p)
45}
46
47impl Hostfxr {
48 pub fn load_from_path(path: impl AsRef<Path>) -> Result<Self, crate::dlopen2::Error> {
50 let path = path.as_ref();
51 let lib = SharedHostfxrLibrary::new(unsafe { Container::load(path) }?);
52
53 let dotnet_exe = PdCString::from_os_str(find_dotnet_bin(path)).unwrap();
55
56 Ok(Self { lib, dotnet_exe })
57 }
58
59 #[cfg(feature = "nethost")]
61 pub fn load_with_nethost() -> Result<Self, crate::nethost::LoadHostfxrError> {
62 crate::nethost::load_hostfxr()
63 }
64
65 #[must_use]
67 pub fn get_dotnet_root(&self) -> PathBuf {
68 self.get_dotnet_exe().parent().unwrap().to_owned()
69 }
70
71 #[must_use]
73 pub fn get_dotnet_exe(&self) -> PathBuf {
74 self.dotnet_exe.to_os_string().into()
75 }
76}
77
78#[repr(transparent)]
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
81pub struct AppOrHostingResult(i32);
82
83impl AppOrHostingResult {
84 #[must_use]
86 pub const fn value(&self) -> i32 {
87 self.0
88 }
89
90 pub fn as_hosting_exit_code(self) -> HostingResult {
92 HostingResult::from(self.0)
93 }
94}
95
96impl From<AppOrHostingResult> for i32 {
97 fn from(code: AppOrHostingResult) -> Self {
98 code.value()
99 }
100}
101
102impl From<i32> for AppOrHostingResult {
103 fn from(code: i32) -> Self {
104 Self(code)
105 }
106}