use core::cmp::Ordering;
use core::hash::Hasher as _;
use crate as rune;
use crate::alloc::fmt::TryWrite;
use crate::alloc::String;
use crate::runtime::{
ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, RuntimeError,
Value, VmResult,
};
use crate::Any;
use crate::{hash_in, ContextError, Hash, Module};
#[rune::module(::std::option)]
pub fn module() -> Result<Module, ContextError> {
let mut m = Module::from_meta(self::module_meta)?;
let mut option = m.ty::<Option<Value>>()?.make_enum(&["Some", "None"])?;
option
.variant_mut(0)?
.make_unnamed(1)?
.constructor(Option::Some)?
.static_docs(&["A some value."])?;
option
.variant_mut(1)?
.make_empty()?
.constructor(|| Option::None)?
.static_docs(&["The empty value."])?;
m.associated_function(
&Protocol::IS_VARIANT,
|this: &Option<Value>, hash: Hash| match (this, hash) {
(Option::Some(_), hash_in!(crate, ::std::option::Option::Some)) => true,
(Option::None, hash_in!(crate, ::std::option::Option::None)) => true,
_ => false,
},
)?;
m.index_function(&Protocol::GET, 0, |this: &Option<Value>| match this {
Option::Some(value) => VmResult::Ok(value.clone()),
_ => VmResult::err(RuntimeError::__rune_macros__unsupported_tuple_index_get(
<Option<Value> as Any>::ANY_TYPE_INFO,
0,
)),
})?;
m.function_meta(expect)?;
m.function_meta(is_some)?;
m.function_meta(is_none)?;
m.function_meta(iter)?;
m.function_meta(into_iter)?;
m.function_meta(and_then)?;
m.function_meta(map)?;
m.function_meta(take)?;
m.function_meta(transpose)?;
m.function_meta(unwrap)?;
m.function_meta(unwrap_or)?;
m.function_meta(unwrap_or_else)?;
m.function_meta(ok_or)?;
m.function_meta(ok_or_else)?;
m.function_meta(clone__meta)?;
m.implement_trait::<Option<Value>>(rune::item!(::std::clone::Clone))?;
m.function_meta(partial_eq__meta)?;
m.implement_trait::<Option<Value>>(rune::item!(::std::cmp::PartialEq))?;
m.function_meta(eq__meta)?;
m.implement_trait::<Option<Value>>(rune::item!(::std::cmp::Eq))?;
m.function_meta(partial_cmp__meta)?;
m.implement_trait::<Option<Value>>(rune::item!(::std::cmp::PartialOrd))?;
m.function_meta(cmp__meta)?;
m.implement_trait::<Option<Value>>(rune::item!(::std::cmp::Ord))?;
m.function_meta(hash__meta)?;
m.function_meta(debug_fmt__meta)?;
m.function_meta(option_try__meta)?;
m.ty::<Iter>()?;
m.function_meta(Iter::next__meta)?;
m.function_meta(Iter::next_back__meta)?;
m.function_meta(Iter::size_hint__meta)?;
m.implement_trait::<Iter>(rune::item!(::std::iter::Iterator))?;
m.implement_trait::<Iter>(rune::item!(::std::iter::DoubleEndedIterator))?;
m.function_meta(Iter::clone__meta)?;
m.implement_trait::<Iter>(rune::item!(::std::clone::Clone))?;
Ok(m)
}
#[rune::function(instance)]
fn expect(option: &Option<Value>, message: Value) -> VmResult<Value> {
match option {
Some(some) => VmResult::Ok(some.clone()),
None => {
let mut s = String::new();
vm_try!(Formatter::format_with(&mut s, |f| message.display_fmt(f)));
VmResult::err(Panic::custom(s))
}
}
}
#[rune::function(instance)]
fn is_some(this: &Option<Value>) -> bool {
this.is_some()
}
#[rune::function(instance)]
fn is_none(this: &Option<Value>) -> bool {
this.is_none()
}
#[rune::function(instance)]
fn iter(value: &Option<Value>) -> Iter {
Iter::new(value.clone())
}
#[rune::function(instance, protocol = INTO_ITER)]
fn into_iter(this: &Option<Value>) -> Iter {
Iter::new(this.clone())
}
#[rune::function(instance)]
fn and_then(option: &Option<Value>, then: Function) -> VmResult<Option<Value>> {
match option {
Some(v) => VmResult::Ok(vm_try!(then.call((v.clone(),)))),
None => VmResult::Ok(None),
}
}
#[rune::function(instance)]
fn map(option: &Option<Value>, then: Function) -> VmResult<Option<Value>> {
match option {
Some(v) => VmResult::Ok(Some(vm_try!(then.call((v.clone(),))))),
None => VmResult::Ok(None),
}
}
#[rune::function(instance)]
fn take(option: &mut Option<Value>) -> Option<Value> {
option.take()
}
#[rune::function(instance)]
fn transpose(this: &Option<Value>) -> VmResult<Value> {
let value = match this {
Some(value) => value,
None => {
let none = vm_try!(Value::try_from(Option::<Value>::None));
let result = vm_try!(Value::try_from(Result::<Value, Value>::Ok(none)));
return VmResult::Ok(result);
}
};
match &*vm_try!(value.borrow_ref::<Result<Value, Value>>()) {
Ok(ok) => {
let some = vm_try!(Value::try_from(Some(ok.clone())));
let result = vm_try!(Value::try_from(Ok(some)));
VmResult::Ok(result)
}
Err(err) => {
let result = vm_try!(Value::try_from(Err(err.clone())));
VmResult::Ok(result)
}
}
}
#[rune::function(instance)]
fn unwrap(option: &Option<Value>) -> VmResult<Value> {
match option {
Some(some) => VmResult::Ok(some.clone()),
None => VmResult::err(Panic::custom("Called `Option::unwrap()` on a `None` value")),
}
}
#[rune::function(instance)]
fn unwrap_or(this: &Option<Value>, default: Value) -> Value {
match this {
Some(value) => value.clone(),
None => default,
}
}
#[rune::function(instance)]
fn unwrap_or_else(this: &Option<Value>, default: Function) -> VmResult<Value> {
match this {
Some(value) => VmResult::Ok(value.clone()),
None => default.call(()),
}
}
#[rune::function(instance)]
fn ok_or(this: &Option<Value>, err: Value) -> Result<Value, Value> {
match this {
Some(value) => Ok(value.clone()),
None => Err(err),
}
}
#[rune::function(instance)]
fn ok_or_else(this: &Option<Value>, err: Function) -> VmResult<Result<Value, Value>> {
match this {
Some(value) => VmResult::Ok(Ok(value.clone())),
None => VmResult::Ok(Err(vm_try!(err.call(())))),
}
}
#[rune::function(keep, instance, protocol = CLONE)]
fn clone(this: &Option<Value>) -> VmResult<Option<Value>> {
VmResult::Ok(match this {
Some(value) => Some(vm_try!(value.clone_with(&mut EnvProtocolCaller))),
None => None,
})
}
#[rune::function(keep, instance, protocol = PARTIAL_EQ)]
#[inline]
fn partial_eq(this: &Option<Value>, rhs: &Option<Value>) -> VmResult<bool> {
match (this, rhs) {
(Some(a), Some(b)) => Value::partial_eq(a, b),
(None, None) => VmResult::Ok(true),
_ => VmResult::Ok(false),
}
}
#[rune::function(keep, instance, protocol = EQ)]
#[inline]
fn eq(this: &Option<Value>, rhs: &Option<Value>) -> VmResult<bool> {
match (this, rhs) {
(Some(a), Some(b)) => Value::eq(a, b),
(None, None) => VmResult::Ok(true),
_ => VmResult::Ok(false),
}
}
#[rune::function(keep, instance, protocol = PARTIAL_CMP)]
#[inline]
fn partial_cmp(this: &Option<Value>, rhs: &Option<Value>) -> VmResult<Option<Ordering>> {
match (this, rhs) {
(Some(a), Some(b)) => Value::partial_cmp(a, b),
(None, None) => VmResult::Ok(Some(Ordering::Equal)),
(Some(..), None) => VmResult::Ok(Some(Ordering::Greater)),
(None, Some(..)) => VmResult::Ok(Some(Ordering::Less)),
}
}
#[rune::function(keep, instance, protocol = CMP)]
#[inline]
fn cmp(this: &Option<Value>, rhs: &Option<Value>) -> VmResult<Ordering> {
match (this, rhs) {
(Some(a), Some(b)) => Value::cmp(a, b),
(None, None) => VmResult::Ok(Ordering::Equal),
(Some(..), None) => VmResult::Ok(Ordering::Greater),
(None, Some(..)) => VmResult::Ok(Ordering::Less),
}
}
#[rune::function(keep, instance, protocol = HASH)]
fn hash(this: &Option<Value>, hasher: &mut Hasher) -> VmResult<()> {
match this {
Some(value) => {
hasher.write_u64(0);
vm_try!(value.hash(hasher));
}
None => {
hasher.write_u64(1);
}
}
VmResult::Ok(())
}
#[rune::function(keep, instance, protocol = DEBUG_FMT)]
#[inline]
fn debug_fmt(this: &Option<Value>, f: &mut Formatter) -> VmResult<()> {
match this {
Some(value) => {
vm_try!(f.try_write_str("Some("));
vm_try!(value.debug_fmt(f));
vm_try!(f.try_write_str(")"));
}
None => {
vm_try!(f.try_write_str("None"));
}
}
VmResult::Ok(())
}
#[rune::function(keep, instance, protocol = TRY)]
pub(crate) fn option_try(this: &Option<Value>) -> VmResult<ControlFlow> {
VmResult::Ok(match this {
Some(value) => ControlFlow::Continue(value.clone()),
None => ControlFlow::Break(vm_try!(Value::try_from(None))),
})
}
#[derive(Any, Clone)]
#[rune(item = ::std::option)]
pub(crate) struct Iter {
value: Option<Value>,
}
impl Iter {
fn new(value: Option<Value>) -> Self {
Self { value }
}
#[rune::function(keep, protocol = NEXT)]
fn next(&mut self) -> Option<Value> {
self.value.take()
}
#[rune::function(keep, protocol = NEXT_BACK)]
fn next_back(&mut self) -> Option<Value> {
self.value.take()
}
#[rune::function(keep, protocol = SIZE_HINT)]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = usize::from(self.value.is_some());
(len, Some(len))
}
#[rune::function(keep, protocol = INTO_ITER)]
fn into_iter(self) -> Self {
self
}
#[rune::function(keep, protocol = CLONE)]
#[inline]
fn clone(&self) -> Self {
Clone::clone(self)
}
}