lean_rs_host/host/host.rs
1//! `LeanHost`—entry point for the host-side capability API.
2//!
3//! A [`LeanHost`] binds a [`lean_rs::LeanRuntime`] borrow to a Lake project
4//! on disk. From it, [`LeanHost::load_capabilities`] opens a compiled user
5//! capability dylib for its module initializers and imports, while
6//! [`LeanHost::load_shims_only`] opens only the bundled host shims for the
7//! standard session services. Both paths return a [`LeanCapabilities`] whose
8//! sessions resolve checked host-shim bindings once and dispatch subsequent
9//! calls without per-call `dlsym`.
10//!
11//! See `docs/architecture/03-host-stack.md` for the full classification
12//! and the host → capabilities → session lifetime cascade.
13
14use core::fmt;
15use std::path::Path;
16
17use lean_rs::LeanRuntime;
18use lean_rs::error::LeanResult;
19use lean_rs::module::LeanLibrary;
20
21use crate::host::capabilities::LeanCapabilities;
22use crate::host::lake::LakeProject;
23
24/// Entry point for hosting Lean capabilities from a Lake project.
25///
26/// Pairs a runtime borrow with a validated Lake project root. Cheap to
27/// construct: only the project root's existence is checked; no dylib
28/// loading happens until [`LeanHost::load_capabilities`] is called.
29///
30/// Neither [`Send`] nor [`Sync`]: inherited from the contained
31/// `&'lean LeanRuntime`.
32pub struct LeanHost<'lean> {
33 runtime: &'lean LeanRuntime,
34 project: LakeProject,
35}
36
37impl fmt::Debug for LeanHost<'_> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("LeanHost").finish_non_exhaustive()
40 }
41}
42
43impl<'lean> LeanHost<'lean> {
44 /// Bind a host to the runtime and a Lake project root directory.
45 ///
46 /// # Errors
47 ///
48 /// Returns [`lean_rs::LeanError::Host`] with stage
49 /// [`lean_rs::HostStage::Load`] if `path` does not exist or is not a
50 /// directory.
51 pub fn from_lake_project(runtime: &'lean LeanRuntime, path: impl AsRef<Path>) -> LeanResult<Self> {
52 let project = LakeProject::new(path)?;
53 Ok(Self { runtime, project })
54 }
55
56 /// Load the compiled capability dylib for the named
57 /// `(package, lib_name)` pair, initialize its root module, and
58 /// prepare the checked host-shim capability used by sessions.
59 ///
60 /// `package` is the Lake package name (e.g. `"lean_rs_fixture"`);
61 /// `lib_name` is the Lake `lean_lib` declaration name and, by
62 /// convention, also the root Lean module path
63 /// (e.g. `"LeanRsFixture"`). For projects where these differ the
64 /// `lib_name` argument is also the module that gets initialised.
65 ///
66 /// # Errors
67 ///
68 /// Returns [`lean_rs::LeanError::Host`] with stage
69 /// [`lean_rs::HostStage::Load`] if the dylib does not exist or fails
70 /// to open. Missing or signature-mismatched mandatory host shims fail when
71 /// constructing a session; optional host shims degrade to `Unsupported` at
72 /// the corresponding call site.
73 pub fn load_capabilities<'h>(&'h self, package: &str, lib_name: &str) -> LeanResult<LeanCapabilities<'lean, 'h>> {
74 let dylib_path = self.project.capability_dylib(package, lib_name);
75 let library = LeanLibrary::open(self.runtime, &dylib_path)?;
76 LeanCapabilities::new(self, library, package, lib_name)
77 }
78
79 /// Load the bundled host-shim and interop dylibs without opening a user
80 /// capability dylib.
81 ///
82 /// Sessions opened from the returned capabilities can import modules from
83 /// this Lake project's `.olean` search path and use the standard
84 /// shim-backed Meta, elaboration, kernel, info-tree, declaration, and
85 /// source-range services.
86 ///
87 /// # Errors
88 ///
89 /// Returns [`lean_rs::LeanError::Host`] with stage
90 /// [`lean_rs::HostStage::Load`] / [`lean_rs::LeanDiagnosticCode::ModuleInit`]
91 /// if the bundled shim or interop dylibs cannot be built or located.
92 /// Returns [`lean_rs::HostStage::Link`] if any mandatory shim symbol is
93 /// missing.
94 pub fn load_shims_only<'h>(&'h self) -> LeanResult<LeanCapabilities<'lean, 'h>> {
95 LeanCapabilities::new_shims_only(self)
96 }
97
98 /// The runtime borrow this host was constructed with.
99 pub(crate) fn runtime(&self) -> &'lean LeanRuntime {
100 self.runtime
101 }
102
103 /// The Lake project root, for capability code that needs to pass
104 /// the path through to Lean (e.g., setting `Lean.searchPathRef`).
105 pub(crate) fn project(&self) -> &LakeProject {
106 &self.project
107 }
108}