derive_deftly_macros/
general_context.rs

1//! Contexts that might not include a driver
2
3use super::framework::*;
4
5use GeneralContext as GC;
6use GeneralContextBuf as GCB;
7
8//==================== types ====================
9
10pub type FullContextResult<'s, 'c> = Result<
11    &'s Context<'c>, //
12    MissingContextError<'c>,
13>;
14
15/// Cheap type that embodies a failed requirement for a driver
16///
17/// This can be pre-obtained and bound to a local `ctx`, and then
18/// converted conveniently to `syn::Error` with `ctx?` when actually
19/// needed.
20#[derive(Clone, Copy)]
21pub struct MissingContextError<'c> {
22    span: Span,
23    error_handler: ErrorGenerator<'c>,
24}
25
26/// Probably a `Context`, but might not be - there might be no driver
27///
28/// Definitely contains a `DefinitionsContext`.
29#[derive(Clone, Copy)]
30pub enum GeneralContext<'c> {
31    Full(&'c Context<'c>),
32    NoDriver(&'c DriverlessContext<'c>),
33}
34
35/// Probably a `Context`, but might not be - there might be no driver
36///
37/// Definitely contains a `DefinitionsContext`.
38#[derive(Clone, Copy)]
39pub enum GeneralContextBuf<'c> {
40    Full(Context<'c>),
41    NoDriver(DriverlessContext<'c>),
42}
43
44#[derive(Clone, Copy)]
45pub struct DriverlessContext<'c> {
46    pub defs: DefinitionsContext<'c>,
47    pub driver_needed: ErrorGenerator<'c>,
48}
49
50//==================== methods on GeneralContext ====================
51
52impl<'c> GeneralContext<'c> {
53    pub fn full_ctx_raw(&self) -> Result<&Context<'c>, ErrorGenerator<'c>> {
54        match self {
55            GC::Full(ctx) => Ok(ctx),
56            GC::NoDriver(dc) => Err(dc.driver_needed),
57        }
58    }
59
60    /// Obtain a full `Context`, in situations where a driver is needed
61    pub fn full_ctx(&self, span: Span) -> FullContextResult<'_, 'c> {
62        self.full_ctx_raw()
63            .map_err(move |error_handler| MissingContextError {
64                span,
65                error_handler,
66            })
67    }
68
69    /// Convenience method.
70    ///
71    /// We could use `.as_ref()` but that is less clear (and risks
72    /// future inference failures).
73    ///
74    /// We don't bother with `defs_mut`.
75    pub fn defs(&self) -> &DefinitionsContext<'c> {
76        self.as_ref()
77    }
78
79    pub fn error_loc(&self) -> Option<ErrorLoc<'c>> {
80        match self {
81            GC::Full(ctx) => Some(ctx.error_loc()),
82            GC::NoDriver { .. } => None,
83        }
84    }
85
86    pub fn prepend_error_loc(
87        &self,
88        rest: &'_ [ErrorLoc<'c>],
89    ) -> Vec<ErrorLoc<'c>> {
90        chain!(
91            self.error_loc(), //
92            rest.iter().copied(),
93        )
94        .collect_vec()
95    }
96
97    pub fn clone_buf(&self) -> GeneralContextBuf<'c> {
98        match self {
99            GC::Full(ctx) => GCB::Full((*ctx).clone()),
100            GC::NoDriver(dc) => GCB::NoDriver((*dc).clone()),
101        }
102    }
103}
104
105impl<'c> AsRef<DefinitionsContext<'c>> for GeneralContext<'c> {
106    fn as_ref(&self) -> &DefinitionsContext<'c> {
107        match self {
108            GC::Full(ctx) => &ctx.defs,
109            GC::NoDriver(dc) => &dc.defs,
110        }
111    }
112}
113
114impl<'c> AsMut<DefinitionsContext<'c>> for GeneralContextBuf<'c> {
115    fn as_mut(&mut self) -> &mut DefinitionsContext<'c> {
116        match self {
117            GCB::Full(ctx) => &mut ctx.defs,
118            GCB::NoDriver(dc) => &mut dc.defs,
119        }
120    }
121}
122
123//==================== display_for_dbg ====================
124
125struct ContextDbgDisplayAdapter<'a>(Option<&'a Context<'a>>);
126
127impl Display for ContextDbgDisplayAdapter<'_> {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129        let ctx = match self.0 {
130            Some(y) => y,
131            None => return write!(f, "[no driver]"),
132        };
133
134        write!(f, "for {}", &ctx.top.ident)?;
135        if let Some(wv) = &ctx.variant {
136            if let Some(v) = &wv.variant {
137                write!(f, "::{}", &v.ident)?;
138            }
139        }
140        if let Some(wf) = &ctx.field {
141            // we're just using the Display impl, any span will do
142            let span = Span::call_site();
143            write!(f, ".{}", &wf.fname(span))?;
144        }
145        if let Some(templ) = &ctx.template_name {
146            let templ = templ.to_token_stream().to_string();
147            write!(f, " from {}", templ)?;
148        }
149        Ok::<_, fmt::Error>(())
150    }
151}
152
153impl<'c> Context<'c> {
154    pub fn display_for_dbg(&self) -> impl Display + '_ {
155        ContextDbgDisplayAdapter(Some(self))
156    }
157}
158
159impl<'c> GeneralContext<'c> {
160    pub fn display_for_dbg(&self) -> impl Display + '_ {
161        ContextDbgDisplayAdapter(match &self {
162            GC::Full(ctx) => Some(ctx),
163            GC::NoDriver { .. } => None,
164        })
165    }
166}
167
168//==================== conversions to/from Context ====================
169
170impl<'c> Context<'c> {
171    pub fn as_general(&'c self) -> GeneralContext<'c> {
172        GC::Full(self)
173    }
174}
175
176impl<'c> GeneralContextBuf<'c> {
177    pub fn as_ref(&'c self) -> GeneralContext<'c> {
178        match self {
179            GCB::Full(ctx) => GC::Full(ctx),
180            GCB::NoDriver(dc) => GC::NoDriver(dc),
181        }
182    }
183}
184
185//==================== remaining impl(s) ====================
186
187impl<'c> From<MissingContextError<'c>> for syn::Error {
188    fn from(e: MissingContextError<'c>) -> syn::Error {
189        (e.error_handler)(e.span)
190    }
191}