use crate::util::AtomicMaybe;
use std::{any::TypeId, fmt::Debug, hash::Hash, sync::atomic::Ordering};
mod options;
mod parse;
mod util;
pub use options::*;
pub use parse::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Status {
OptIn,
OptOut,
DeprecatedDefault,
DeprecatedDiscard,
}
pub struct ExperimentalOption {
value: AtomicMaybe,
marker: &'static (dyn DynExperimentalOptionMarker + Send + Sync),
}
impl ExperimentalOption {
pub(crate) const fn new(
marker: &'static (dyn DynExperimentalOptionMarker + Send + Sync),
) -> Self {
Self {
value: AtomicMaybe::new(None),
marker,
}
}
pub fn identifier(&self) -> &'static str {
self.marker.identifier()
}
pub fn description(&self) -> &'static str {
self.marker.description()
}
pub fn status(&self) -> Status {
self.marker.status()
}
pub fn since(&self) -> Version {
self.marker.since()
}
pub fn issue_id(&self) -> u32 {
self.marker.issue()
}
pub fn issue_url(&self) -> String {
format!(
"https://github.com/nushell/nushell/issues/{}",
self.marker.issue()
)
}
pub fn get(&self) -> bool {
self.value
.load(Ordering::Relaxed)
.unwrap_or_else(|| match self.marker.status() {
Status::OptIn => false,
Status::OptOut => true,
Status::DeprecatedDiscard => false,
Status::DeprecatedDefault => false,
})
}
pub unsafe fn set(&self, value: bool) {
self.value.store(value, Ordering::Relaxed);
}
pub unsafe fn unset(&self) {
self.value.store(None, Ordering::Relaxed);
}
}
impl Debug for ExperimentalOption {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let add_description = f.sign_plus();
let mut debug_struct = f.debug_struct("ExperimentalOption");
debug_struct.field("identifier", &self.identifier());
debug_struct.field("value", &self.get());
debug_struct.field("status", &self.status());
if add_description {
debug_struct.field("description", &self.description());
}
debug_struct.finish()
}
}
impl PartialEq for ExperimentalOption {
fn eq(&self, other: &Self) -> bool {
self.value.as_ptr() == other.value.as_ptr()
}
}
impl Eq for ExperimentalOption {}
impl PartialOrd for ExperimentalOption {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ExperimentalOption {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.identifier().cmp(other.identifier())
}
}
impl Hash for ExperimentalOption {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
TypeId::of::<Self>().hash(state);
self.identifier().hash(state);
}
}
pub unsafe fn set_all(value: bool) {
for option in ALL {
match option.status() {
Status::OptIn | Status::OptOut => unsafe { option.set(value) },
Status::DeprecatedDefault | Status::DeprecatedDiscard => {}
}
}
}
pub(crate) trait DynExperimentalOptionMarker {
fn identifier(&self) -> &'static str;
fn description(&self) -> &'static str;
fn status(&self) -> Status;
fn since(&self) -> Version;
fn issue(&self) -> u32;
}
impl<M: options::ExperimentalOptionMarker> DynExperimentalOptionMarker for M {
fn identifier(&self) -> &'static str {
M::IDENTIFIER
}
fn description(&self) -> &'static str {
M::DESCRIPTION
}
fn status(&self) -> Status {
M::STATUS
}
fn since(&self) -> Version {
M::SINCE
}
fn issue(&self) -> u32 {
M::ISSUE
}
}