typst_pack/
package_failure.rs1use std::collections::BTreeMap;
4
5use typst::syntax::package::{PackageSpec, PackageVersion};
6
7#[derive(Clone, Debug, Default, Eq, PartialEq)]
13pub struct PackageReadFailures {
14 failures: BTreeMap<String, PackageReadFailure>,
15}
16
17impl PackageReadFailures {
18 pub fn new() -> Self {
20 Self::default()
21 }
22
23 pub fn insert(&mut self, failure: PackageReadFailure) -> Option<PackageReadFailure> {
25 self.failures.insert(failure.spec.to_string(), failure)
26 }
27
28 pub fn entries(&self) -> impl Iterator<Item = &PackageReadFailure> {
30 self.failures.values()
31 }
32
33 pub fn get(&self, spec: &PackageSpec) -> Option<&PackageReadFailure> {
35 self.failures.get(&spec.to_string())
36 }
37
38 #[cfg(any(feature = "fs", all(feature = "opendal", feature = "package-reading")))]
40 pub(crate) fn remove(&mut self, spec: &PackageSpec) -> Option<PackageReadFailure> {
41 self.failures.remove(&spec.to_string())
42 }
43}
44
45impl FromIterator<PackageReadFailure> for PackageReadFailures {
46 fn from_iter<T: IntoIterator<Item = PackageReadFailure>>(failures: T) -> Self {
47 let mut result = Self::new();
48 for failure in failures {
49 result.insert(failure);
50 }
51 result
52 }
53}
54
55#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
57#[error("failed to read {spec}: {reason}")]
58pub struct PackageReadFailure {
59 spec: PackageSpec,
60 reason: PackageReadFailureReason,
61}
62
63impl PackageReadFailure {
64 pub fn new(spec: PackageSpec, reason: PackageReadFailureReason) -> Self {
65 Self { spec, reason }
66 }
67
68 pub fn spec(&self) -> &PackageSpec {
70 &self.spec
71 }
72
73 pub fn reason(&self) -> &PackageReadFailureReason {
75 &self.reason
76 }
77
78 pub fn into_parts(self) -> (PackageSpec, PackageReadFailureReason) {
79 (self.spec, self.reason)
80 }
81}
82
83#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
85#[non_exhaustive]
86pub enum PackageReadFailureReason {
87 #[error("package not found")]
88 NotFound,
89 #[error("package version not found; latest available version is {latest}")]
90 VersionNotFound { latest: PackageVersion },
91 #[error("network request failed{detail}", detail = optional_detail(.detail))]
92 NetworkFailed { detail: Option<String> },
93 #[error("package archive is malformed{detail}", detail = optional_detail(.detail))]
94 MalformedArchive { detail: Option<String> },
95 #[error("package read failed{detail}", detail = optional_detail(.detail))]
96 Other { detail: Option<String> },
97}
98
99fn optional_detail(detail: &Option<String>) -> String {
100 detail
101 .as_ref()
102 .map(|detail| format!(": {detail:?}"))
103 .unwrap_or_default()
104}