use std::path::{Path, PathBuf};
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum LeanLoaderDiagnosticCode {
MissingManifest,
MalformedManifest,
UnsupportedManifestSchema,
MissingPrimaryDylib,
MissingTransitiveDependency,
UnsupportedArchitecture,
UnsupportedToolchainFingerprint,
StaleManifest,
MissingInitializer,
MissingImportedSymbol,
}
impl LeanLoaderDiagnosticCode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::MissingManifest => "lean_rs.loader.missing_manifest",
Self::MalformedManifest => "lean_rs.loader.malformed_manifest",
Self::UnsupportedManifestSchema => "lean_rs.loader.unsupported_manifest_schema",
Self::MissingPrimaryDylib => "lean_rs.loader.missing_primary_dylib",
Self::MissingTransitiveDependency => "lean_rs.loader.missing_transitive_dependency",
Self::UnsupportedArchitecture => "lean_rs.loader.unsupported_architecture",
Self::UnsupportedToolchainFingerprint => "lean_rs.loader.unsupported_toolchain_fingerprint",
Self::StaleManifest => "lean_rs.loader.stale_manifest",
Self::MissingInitializer => "lean_rs.loader.missing_initializer",
Self::MissingImportedSymbol => "lean_rs.loader.missing_imported_symbol",
}
}
}
impl std::fmt::Display for LeanLoaderDiagnosticCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub enum LeanLoaderSeverity {
Info,
Warning,
Error,
}
pub const LOADER_DIAGNOSTIC_TEXT_LIMIT: usize = 4 * 1024;
#[must_use]
pub fn bound_loader_text(mut text: String) -> String {
if text.len() <= LOADER_DIAGNOSTIC_TEXT_LIMIT {
return text;
}
let mut cut = LOADER_DIAGNOSTIC_TEXT_LIMIT;
while cut > 0 && !text.is_char_boundary(cut) {
cut = cut.saturating_sub(1);
}
text.truncate(cut);
text
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LeanLoaderCheck {
code: LeanLoaderDiagnosticCode,
severity: LeanLoaderSeverity,
subject: String,
message: String,
repair_hint: String,
}
impl LeanLoaderCheck {
#[must_use]
pub fn error(
code: LeanLoaderDiagnosticCode,
subject: impl Into<String>,
message: impl Into<String>,
repair_hint: impl Into<String>,
) -> Self {
Self {
code,
severity: LeanLoaderSeverity::Error,
subject: bound_loader_text(subject.into()),
message: bound_loader_text(message.into()),
repair_hint: bound_loader_text(repair_hint.into()),
}
}
#[must_use]
pub fn code(&self) -> LeanLoaderDiagnosticCode {
self.code
}
#[must_use]
pub fn severity(&self) -> LeanLoaderSeverity {
self.severity
}
#[must_use]
pub fn subject(&self) -> &str {
&self.subject
}
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
#[must_use]
pub fn repair_hint(&self) -> &str {
&self.repair_hint
}
}
impl std::fmt::Display for LeanLoaderCheck {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} [{:?}] {}: {} (repair: {})",
self.code.as_str(),
self.severity,
self.subject,
self.message,
self.repair_hint
)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LeanLoaderReport {
manifest_path: Option<PathBuf>,
checks: Vec<LeanLoaderCheck>,
}
impl LeanLoaderReport {
#[must_use]
pub fn new(manifest_path: Option<PathBuf>, checks: Vec<LeanLoaderCheck>) -> Self {
Self { manifest_path, checks }
}
#[must_use]
pub fn manifest_path(&self) -> Option<&Path> {
self.manifest_path.as_deref()
}
#[must_use]
pub fn checks(&self) -> &[LeanLoaderCheck] {
&self.checks
}
pub fn errors(&self) -> impl Iterator<Item = &LeanLoaderCheck> {
self.checks
.iter()
.filter(|check| check.severity == LeanLoaderSeverity::Error)
}
#[must_use]
pub fn is_ok(&self) -> bool {
self.errors().next().is_none()
}
#[must_use]
pub fn first_error(&self) -> Option<&LeanLoaderCheck> {
self.errors().next()
}
#[must_use]
pub fn into_checks(self) -> Vec<LeanLoaderCheck> {
self.checks
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LeanModuleInitializer {
package: String,
module: String,
}
impl LeanModuleInitializer {
#[must_use]
pub fn new(package: impl Into<String>, module: impl Into<String>) -> Self {
Self {
package: package.into(),
module: module.into(),
}
}
#[must_use]
pub fn package_name(&self) -> &str {
&self.package
}
#[must_use]
pub fn module_name(&self) -> &str {
&self.module
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LeanLibraryDependency {
path: PathBuf,
exports_symbols_for_dependents: bool,
initializer: Option<LeanModuleInitializer>,
}
impl LeanLibraryDependency {
#[must_use]
pub fn path(path: impl Into<PathBuf>) -> Self {
Self {
path: path.into(),
exports_symbols_for_dependents: false,
initializer: None,
}
}
#[must_use]
pub fn export_symbols_for_dependents(mut self) -> Self {
self.exports_symbols_for_dependents = true;
self
}
#[must_use]
pub fn initializer(mut self, package: impl Into<String>, module: impl Into<String>) -> Self {
self.initializer = Some(LeanModuleInitializer::new(package, module));
self
}
#[must_use]
pub fn path_ref(&self) -> &Path {
&self.path
}
#[must_use]
pub fn exports_symbols_for_dependents(&self) -> bool {
self.exports_symbols_for_dependents
}
#[must_use]
pub fn module_initializer(&self) -> Option<&LeanModuleInitializer> {
self.initializer.as_ref()
}
#[must_use]
pub fn into_module_initializer(self) -> Option<LeanModuleInitializer> {
self.initializer
}
}