use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::sync::atomic::AtomicU8;
use std::sync::atomic::Ordering::*;
use std::{fmt, ops};
const UNINIT: u8 = 0;
const IN_PROGRESS: u8 = 1;
const INIT: u8 = 2;
struct OnceCell<T> {
value: MaybeUninit<UnsafeCell<T>>,
state: AtomicU8,
}
unsafe impl<T: Send + Sync> Sync for OnceCell<T> {}
unsafe impl<T: Send> Send for OnceCell<T> {}
impl<T> OnceCell<T> {
pub const fn new() -> Self {
Self {
value: MaybeUninit::uninit(),
state: AtomicU8::new(UNINIT),
}
}
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
struct Guard<'a> {
state: &'a AtomicU8,
new_state: u8,
}
impl<'a> Drop for Guard<'a> {
fn drop(&mut self) {
self.state.store(self.new_state, Release);
}
}
loop {
match self
.state
.compare_exchange_weak(UNINIT, IN_PROGRESS, Acquire, Acquire)
{
Ok(_) => {
let slot = unsafe { &mut *self.value.assume_init_ref().get() };
let mut guard = Guard {
state: &self.state,
new_state: UNINIT,
};
*slot = f();
guard.new_state = INIT;
break slot;
}
Err(INIT) => {
break unsafe { &*self.value.assume_init_ref().get() };
}
Err(IN_PROGRESS | UNINIT) => {
std::thread::yield_now();
}
Err(_) => unsafe {
std::hint::unreachable_unchecked();
},
}
}
}
}
pub struct Args {
cache: OnceCell<Box<[Box<str>]>>,
}
impl Args {
const fn new() -> Self {
Self {
cache: OnceCell::new(),
}
}
fn force(&self) -> &[Box<str>] {
self.cache
.get_or_init(|| std::env::args().map(String::into_boxed_str).collect())
}
#[inline]
pub fn len(&self) -> usize {
self.force().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.force().is_empty()
}
}
impl fmt::Debug for Args {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self.force(), f)
}
}
impl ops::Index<usize> for Args {
type Output = str;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.force()[index]
}
}
#[derive(Debug, Clone)]
pub struct ArgsIter<'a> {
inner: std::slice::Iter<'a, Box<str>>,
}
impl<'a> Iterator for ArgsIter<'a> {
type Item = &'a str;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(Box::as_ref)
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline(always)]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.inner.nth(n).map(Box::as_ref)
}
#[inline(always)]
fn count(self) -> usize
where
Self: Sized,
{
self.inner.count()
}
}
impl<'a> DoubleEndedIterator for ArgsIter<'a> {
#[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back().map(Box::as_ref)
}
#[inline(always)]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.inner.nth_back(n).map(Box::as_ref)
}
}
impl<'a> ExactSizeIterator for ArgsIter<'a> {
#[inline(always)]
fn len(&self) -> usize {
self.inner.len()
}
}
impl<'a> IntoIterator for &'a Args {
type Item = &'a str;
type IntoIter = ArgsIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ArgsIter {
inner: self.force().iter(),
}
}
}
pub static ARGS: &Args = {
static STORAGE: Args = Args::new();
&STORAGE
};