Skip to main content

tendrils_core/
tendril_report.rs

1use crate::{
2    FsoType,
3    InvalidTendrilError,
4    RawTendril,
5    TendrilActionError,
6    TendrilActionSuccess,
7};
8use std::marker::PhantomData;
9use std::path::PathBuf;
10
11/// Generic report format for any operation on a [`RawTendril`]
12#[derive(Clone, Debug, Eq, PartialEq)]
13pub struct TendrilReport<T: TendrilLog> {
14    /// The original tendril bundle that this tendril was expanded from.
15    pub raw_tendril: RawTendril,
16
17    /// Result containing the log from the operation, provided
18    /// the tendril was valid.
19    /// Otherwise, it contains the [`InvalidTendrilError`].
20    pub log: Result<T, InvalidTendrilError>,
21}
22
23/// Generic log information for any operation on a tendril
24pub trait TendrilLog {
25    /// The type of the file system object in the Tendrils repo.
26    /// `None` if it does not exist.
27    fn local_type(&self) -> &Option<FsoType>;
28
29    /// The type of the file system object at its device-specific
30    /// location.
31    /// `None` if it does not exist.
32    fn remote_type(&self) -> &Option<FsoType>;
33
34    /// The full path to the remote. This shows the result after resolving
35    /// all environment/other variables in the path.
36    fn resolved_path(&self) -> &PathBuf;
37}
38
39/// Contains the metadata from a single tendrils action.
40#[derive(Clone, Debug, Eq, PartialEq)]
41pub struct ActionLog {
42    local_type: Option<FsoType>,
43    remote_type: Option<FsoType>,
44    resolved_path: PathBuf,
45    /// Result of this individual action.
46    pub result: Result<TendrilActionSuccess, TendrilActionError>,
47}
48
49impl ActionLog {
50    pub fn new(
51        local_type: Option<FsoType>,
52        remote_type: Option<FsoType>,
53        resolved_path: PathBuf,
54        result: Result<TendrilActionSuccess, TendrilActionError>,
55    ) -> ActionLog {
56        ActionLog { local_type, remote_type, resolved_path, result }
57    }
58}
59
60impl TendrilLog for ActionLog {
61    fn local_type(&self) -> &Option<FsoType> {
62        &self.local_type
63    }
64
65    fn remote_type(&self) -> &Option<FsoType> {
66        &self.remote_type
67    }
68
69    fn resolved_path(&self) -> &PathBuf {
70        &self.resolved_path
71    }
72}
73
74/// Contains the metadata from a single tendril.
75#[derive(Clone, Debug, Eq, PartialEq)]
76pub struct ListLog {
77    local_type: Option<FsoType>,
78    remote_type: Option<FsoType>,
79    resolved_path: PathBuf,
80}
81
82impl ListLog {
83    pub fn new(
84        local_type: Option<FsoType>,
85        remote_type: Option<FsoType>,
86        resolved_path: PathBuf,
87    ) -> ListLog {
88        ListLog { local_type, remote_type, resolved_path }
89    }
90}
91
92impl TendrilLog for ListLog {
93    fn local_type(&self) -> &Option<FsoType> {
94        &self.local_type
95    }
96
97    fn remote_type(&self) -> &Option<FsoType> {
98        &self.remote_type
99    }
100
101    fn resolved_path(&self) -> &PathBuf {
102        &self.resolved_path
103    }
104}
105
106/// Contains various updater functions for live feedback during a tendrils
107/// command.
108pub trait UpdateHandler<L>
109where
110    L: TendrilLog
111{
112    /// Accepts `value` indicating the total count
113    /// of all raw tendrils that will be processed.
114    fn count(&mut self, value: i32);
115
116    /// Accepts `raw` indicating the tendril that will be processed.
117    /// This is called *before* processing.
118    fn before(&mut self, raw: RawTendril);
119
120    /// Accepts `report` containing the result of the operation.
121    /// This is called *after* processing.
122    fn after(&mut self, report: TendrilReport<L>);
123}
124
125/// Accepts callbacks to be called by the [`UpdateHandler`] methods.
126pub struct CallbackUpdater<A, B, C, L>
127where
128    A: FnMut(TendrilReport<L>),
129    B: FnMut(RawTendril),
130    C: FnMut(i32),
131    L: TendrilLog,
132{
133    pub count: C,
134    pub before: B,
135    pub after: A,
136    _marker: PhantomData<L>,
137}
138
139impl<A, B, C, L> CallbackUpdater<A, B, C, L>
140where
141    A: FnMut(TendrilReport<L>),
142    B: FnMut(RawTendril),
143    C: FnMut(i32),
144    L: TendrilLog,
145{
146    pub fn new(count: C, before: B, after: A) -> CallbackUpdater<A, B, C, L> {
147        CallbackUpdater {
148            count,
149            before,
150            after,
151            _marker: PhantomData,
152        }
153    }
154
155    #[cfg(test)]
156    pub fn default() -> CallbackUpdater<impl FnMut(TendrilReport<L>), impl FnMut(RawTendril), impl FnMut(i32), L> {
157        CallbackUpdater {
158            count: |_| {},
159            before: |_| {},
160            after: |_| {},
161            _marker: PhantomData,
162        }
163    }
164}
165
166impl<A, B, C, L> UpdateHandler<L> for CallbackUpdater<A, B, C, L>
167where
168    A: FnMut(TendrilReport<L>),
169    B: FnMut(RawTendril),
170    C: FnMut(i32),
171    L: TendrilLog,
172{
173    fn count(&mut self, total: i32) {
174        (self.count)(total)
175    }
176
177    fn before(&mut self, raw: RawTendril) {
178        (self.before)(raw)
179    }
180
181    fn after(&mut self, report: TendrilReport<L>) {
182        (self.after)(report)
183    }
184}