use std::ptr;
static RESTRICTED_VALUE: StandardExpressionExecutionContext = StandardExpressionExecutionContext {
restrict_variable_access: true,
restrict_external_access: true,
forbid_unsafe_expression_results: false,
perform_type_conversion: false,
};
static RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_VALUE: StandardExpressionExecutionContext =
StandardExpressionExecutionContext {
restrict_variable_access: true,
restrict_external_access: true,
forbid_unsafe_expression_results: true,
perform_type_conversion: false,
};
static NORMAL_VALUE: StandardExpressionExecutionContext = StandardExpressionExecutionContext {
restrict_variable_access: false,
restrict_external_access: false,
forbid_unsafe_expression_results: false,
perform_type_conversion: false,
};
static RESTRICTED_WITH_TYPE_CONVERSION_VALUE: StandardExpressionExecutionContext =
StandardExpressionExecutionContext {
restrict_variable_access: true,
restrict_external_access: true,
forbid_unsafe_expression_results: false,
perform_type_conversion: true,
};
static RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION_VALUE:
StandardExpressionExecutionContext = StandardExpressionExecutionContext {
restrict_variable_access: true,
restrict_external_access: true,
forbid_unsafe_expression_results: true,
perform_type_conversion: true,
};
static NORMAL_WITH_TYPE_CONVERSION_VALUE: StandardExpressionExecutionContext =
StandardExpressionExecutionContext {
restrict_variable_access: false,
restrict_external_access: false,
forbid_unsafe_expression_results: false,
perform_type_conversion: true,
};
#[derive(Debug)]
pub struct StandardExpressionExecutionContext {
restrict_variable_access: bool,
restrict_external_access: bool,
forbid_unsafe_expression_results: bool,
perform_type_conversion: bool,
}
impl StandardExpressionExecutionContext {
pub const RESTRICTED: &'static Self = &RESTRICTED_VALUE;
pub const RESTRICTED_FORBID_UNSAFE_EXP_RESULTS: &'static Self =
&RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_VALUE;
pub const NORMAL: &'static Self = &NORMAL_VALUE;
#[must_use]
pub const fn get_restrict_variable_access(&self) -> bool {
self.restrict_variable_access
}
#[must_use]
pub const fn get_restrict_external_access(&self) -> bool {
self.restrict_external_access
}
#[must_use]
pub const fn get_forbid_unsafe_expression_results(&self) -> bool {
self.forbid_unsafe_expression_results
}
#[must_use]
pub const fn get_perform_type_conversion(&self) -> bool {
self.perform_type_conversion
}
#[must_use]
pub fn without_type_conversion(&'static self) -> &'static Self {
if !self.get_perform_type_conversion() {
return self;
}
if ptr::eq(self, &NORMAL_WITH_TYPE_CONVERSION_VALUE) {
return Self::NORMAL;
}
if ptr::eq(self, &RESTRICTED_WITH_TYPE_CONVERSION_VALUE) {
return Self::RESTRICTED;
}
debug_assert!(ptr::eq(
self,
&RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION_VALUE
));
Self::RESTRICTED_FORBID_UNSAFE_EXP_RESULTS
}
#[must_use]
pub fn with_type_conversion(&'static self) -> &'static Self {
if self.get_perform_type_conversion() {
return self;
}
if ptr::eq(self, Self::NORMAL) {
return &NORMAL_WITH_TYPE_CONVERSION_VALUE;
}
if ptr::eq(self, Self::RESTRICTED) {
return &RESTRICTED_WITH_TYPE_CONVERSION_VALUE;
}
debug_assert!(ptr::eq(self, Self::RESTRICTED_FORBID_UNSAFE_EXP_RESULTS));
&RESTRICTED_FORBID_UNSAFE_EXP_RESULTS_WITH_TYPE_CONVERSION_VALUE
}
}
#[cfg(test)]
mod tests {
use std::ptr;
use super::StandardExpressionExecutionContext;
#[test]
fn preserves_flags_and_singleton_identity_across_conversion_switches() {
let contexts = [
StandardExpressionExecutionContext::NORMAL,
StandardExpressionExecutionContext::RESTRICTED,
StandardExpressionExecutionContext::RESTRICTED_FORBID_UNSAFE_EXP_RESULTS,
];
let expected = [
(false, false, false),
(true, true, false),
(true, true, true),
];
for (context, flags) in contexts.into_iter().zip(expected) {
assert_eq!(context.get_restrict_variable_access(), flags.0);
assert_eq!(context.get_restrict_external_access(), flags.1);
assert_eq!(context.get_forbid_unsafe_expression_results(), flags.2);
assert!(!context.get_perform_type_conversion());
assert!(ptr::eq(context.without_type_conversion(), context));
let converted = context.with_type_conversion();
assert!(converted.get_perform_type_conversion());
assert!(ptr::eq(converted.with_type_conversion(), converted));
assert!(ptr::eq(converted.without_type_conversion(), context));
}
}
}