File: beta.rs

package info (click to toggle)
rust-derive-deftly 1.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,652 kB
  • sloc: perl: 1,032; sh: 373; python: 227; makefile: 11
file content (130 lines) | stat: -rw-r--r-- 4,160 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Handle `beta_deftly` template option, when `beta` cargo feature enabled
//!
//! For instructions on adding a beta feature,
//! see [`beta::Enabled`].
//!
//! This is a bit annoying.  It has to be an ambient property,
//! so that the syn `Parse` trait can be implemented.

use super::prelude::*;

use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};

/// Token indicating that beta feature(s) are or can be enabled
///
/// When adding a new beta feature:
///
///  * Put an instance of [`beta::Enabled`]
///    in the appropriate piece of parsed template syntax,
///    For example, in the [`SubstDetails`](super::syntax::SubstDetails)
///    along with the `O::` markers.
///
///  * When parsing, obtain the value from [`Enabled::new_for_syntax`].
///
///  * Add a test case to `tests/minimal-ui/disabled.rs`
///    which *omits* the `beta_deftly` option, and therefore fails,
///    thus demonstrating that the feature gate works as intended.
///
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[non_exhaustive]
pub struct Enabled {}

pub type MaybeEnabled = Result<Enabled, ErrorGenerator<'static>>;

#[derive(Copy, Clone)]
enum ThreadState {
    Unset,
    Set(MaybeEnabled),
}

use ThreadState as TS;

thread_local! {
    static ENABLED: Cell<ThreadState> = Cell::new(TS::Unset);
}

/// Workaround for `LazyStatic<Cell>::get` MSRV of 1.73.0.
fn threadlocal_get() -> ThreadState {
    ENABLED.with(|c| c.get())
}
fn threadlocal_set(s: ThreadState) {
    ENABLED.with(|c| c.set(s))
}

/// Call `f` with beta features enabled or not
///
/// Used by the parser for `TopTemplate`
pub fn with_maybe_enabled<R>(
    enabled: MaybeEnabled,
    f: impl FnOnce() -> R,
) -> R {
    assert!(matches!(threadlocal_get(), TS::Unset));
    threadlocal_set(TS::Set(enabled));
    // Unwind safety: we re-throw the panic,
    // so even if f or R wasn't, no-one observes any broken invariant.
    let r = catch_unwind(AssertUnwindSafe(f));
    threadlocal_set(TS::Unset);
    match r {
        Ok(r) => r,
        Err(e) => resume_unwind(e),
    }
}

impl Enabled {
    /// If the cargo feature is enabled, return `Ok(Enabled)`
    ///
    /// Used when parsing the `beta_deftly` template option.
    //
    // (In this version of the source code it *always* returns Ok.
    // Returning Err is done by beta_disabled.rs.)
    pub fn new_for_dd_option(_: Span) -> syn::Result<Self> {
        Ok(Enabled {})
    }

    /// If the cargo feature is enabled, return `Ok(Enabled)`
    ///
    /// Used for things that are inherently part of the modules feature,
    /// such as `use`s and `define_derive_deftly_module!`.
    //
    // Remove when modules are no longer beta
    //
    // (In this version of the source code it *always* returns Ok.
    // Returning Err is done by beta_disabled.rs.)
    pub fn new_for_modules_feature(_: Span) -> syn::Result<Self> {
        Ok(Enabled {})
    }

    /// If the cargo feature is enabled, return `Some`.
    ///
    /// Used when parsing template text imported from modules.
    ///
    /// The rule is that modules have their own `beta_deftly` option,
    /// and beta features are allowed in module text iff the module
    /// enabled them.  The importing template doesn't need to.
    //
    // (In this version of the source code it *always* returns Ok.
    // Returning Err is done by beta_disabled.rs.)
    pub fn new_for_imported_definitions() -> MaybeEnabled {
        Ok(Enabled {})
    }

    /// If the `beta_deftly` template feature is enabled, return `Ok(Enabled)`
    ///
    /// Used when parsing beta syntax, in templates.
    #[allow(dead_code)] // sometimes we might not have any beta features
    pub fn new_for_syntax(span: Span) -> syn::Result<Self> {
        match threadlocal_get() {
            TS::Unset => {
                Err(span.error("internal error! beta::ENABLED Unset"))
            }
            TS::Set(ue) => ue.map_err(|eh| eh(span)),
        }
    }

    /// Makes `new_for_syntax` work properly within `f`, in test cases
    #[cfg(test)]
    #[allow(dead_code)]
    pub fn test_with_parsing<R>(f: impl FnOnce() -> R) -> R {
        with_maybe_enabled(Ok(Enabled {}), f)
    }
}