use core::cmp::Ordering;
use core::hash::Hasher as _;
use crate as rune;
use crate::alloc::fmt::TryWrite;
use crate::alloc::prelude::*;
use crate::runtime::{
ControlFlow, EnvProtocolCaller, Formatter, Function, Hasher, Panic, Protocol, Value, VmResult,
};
use crate::{hash_in, ContextError, Hash, Module};
#[rune::module(::std::result)]
pub fn module() -> Result<Module, ContextError> {
let mut m = Module::from_meta(self::module_meta)?;
let mut result = m
.ty::<Result<Value, Value>>()?
.static_docs(&["Result is a type that represents either success (Ok) or failure (Err)."])?
.make_enum(&["Ok", "Err"])?;
result
.variant_mut(0)?
.make_unnamed(1)?
.constructor(Result::Ok)?
.static_docs(&["Contains the success value"])?;
result
.variant_mut(1)?
.make_unnamed(1)?
.constructor(Result::Err)?
.static_docs(&["Contains the error value"])?;
m.associated_function(
&Protocol::IS_VARIANT,
|this: &Result<Value, Value>, hash: Hash| match (this, hash) {
(Result::Ok(_), hash_in!(crate, ::std::result::Result::Ok)) => true,
(Result::Err(_), hash_in!(crate, ::std::result::Result::Err)) => true,
_ => false,
},
)?;
m.index_function(
&Protocol::GET,
0,
|this: &Result<Value, Value>| match this {
Result::Ok(value) => VmResult::Ok(value.clone()),
Result::Err(value) => VmResult::Ok(value.clone()),
},
)?;
m.function_meta(ok)?;
m.function_meta(is_ok)?;
m.function_meta(is_err)?;
m.function_meta(unwrap)?;
m.function_meta(unwrap_or)?;
m.function_meta(unwrap_or_else)?;
m.function_meta(expect)?;
m.function_meta(and_then)?;
m.function_meta(map)?;
m.function_meta(clone__meta)?;
m.implement_trait::<Result<Value, Value>>(rune::item!(::std::clone::Clone))?;
m.function_meta(partial_eq__meta)?;
m.implement_trait::<Result<Value, Value>>(rune::item!(::std::cmp::PartialEq))?;
m.function_meta(eq__meta)?;
m.implement_trait::<Result<Value, Value>>(rune::item!(::std::cmp::Eq))?;
m.function_meta(partial_cmp__meta)?;
m.implement_trait::<Result<Value, Value>>(rune::item!(::std::cmp::PartialOrd))?;
m.function_meta(cmp__meta)?;
m.implement_trait::<Result<Value, Value>>(rune::item!(::std::cmp::Ord))?;
m.function_meta(hash__meta)?;
m.function_meta(debug_fmt__meta)?;
m.function_meta(result_try__meta)?;
Ok(m)
}
#[rune::function(instance)]
fn ok(result: &Result<Value, Value>) -> Option<Value> {
result.as_ref().ok().cloned()
}
#[rune::function(instance)]
fn is_ok(result: &Result<Value, Value>) -> bool {
result.is_ok()
}
#[rune::function(instance)]
fn is_err(result: &Result<Value, Value>) -> bool {
result.is_err()
}
#[rune::function(instance)]
fn unwrap(result: &Result<Value, Value>) -> VmResult<Value> {
match result {
Ok(value) => VmResult::Ok(value.clone()),
Err(err) => {
let mut m = String::new();
vm_try!(vm_write!(
m,
"Called `Result::unwrap()` on an `Err` value: "
));
vm_try!(Formatter::format_with(&mut m, |f| err.debug_fmt(f)));
VmResult::err(Panic::custom(m))
}
}
}
#[rune::function(instance)]
fn unwrap_or(this: &Result<Value, Value>, default: Value) -> Value {
match this {
Ok(value) => value.clone(),
Err(_) => default.clone(),
}
}
#[rune::function(instance)]
fn unwrap_or_else(this: &Result<Value, Value>, default: Function) -> VmResult<Value> {
match this {
Ok(value) => VmResult::Ok(value.clone()),
Err(error) => default.call((error,)),
}
}
#[rune::function(instance)]
fn expect(result: &Result<Value, Value>, message: Value) -> VmResult<Value> {
match result {
Ok(value) => VmResult::Ok(value.clone()),
Err(err) => {
let mut s = String::new();
vm_try!(Formatter::format_with(&mut s, |f| {
vm_try!(message.display_fmt(f));
vm_try!(f.try_write_str(": "));
vm_try!(err.debug_fmt(f));
VmResult::Ok(())
}));
VmResult::err(Panic::custom(s))
}
}
}
#[rune::function(instance)]
fn and_then(this: &Result<Value, Value>, op: Function) -> VmResult<Result<Value, Value>> {
match this {
Ok(v) => VmResult::Ok(vm_try!(op.call((v,)))),
Err(e) => VmResult::Ok(Err(e.clone())),
}
}
#[rune::function(instance)]
fn map(this: &Result<Value, Value>, then: Function) -> VmResult<Result<Value, Value>> {
match this {
Ok(v) => VmResult::Ok(Ok(vm_try!(then.call((v,))))),
Err(e) => VmResult::Ok(Err(e.clone())),
}
}
#[rune::function(keep, instance, protocol = CLONE)]
fn clone(this: &Result<Value, Value>) -> VmResult<Result<Value, Value>> {
VmResult::Ok(match this {
Ok(ok) => Ok(vm_try!(ok.clone_with(&mut EnvProtocolCaller))),
Err(err) => Err(vm_try!(err.clone_with(&mut EnvProtocolCaller))),
})
}
#[rune::function(keep, instance, protocol = PARTIAL_EQ)]
#[inline]
fn partial_eq(this: &Result<Value, Value>, rhs: &Result<Value, Value>) -> VmResult<bool> {
match (this, rhs) {
(Ok(a), Ok(b)) => Value::partial_eq(a, b),
(Err(a), Err(b)) => Value::partial_eq(a, b),
_ => VmResult::Ok(false),
}
}
#[rune::function(keep, instance, protocol = EQ)]
#[inline]
fn eq(this: &Result<Value, Value>, rhs: &Result<Value, Value>) -> VmResult<bool> {
match (this, rhs) {
(Ok(a), Ok(b)) => Value::eq(a, b),
(Err(a), Err(b)) => Value::eq(a, b),
_ => VmResult::Ok(false),
}
}
#[rune::function(keep, instance, protocol = PARTIAL_CMP)]
#[inline]
fn partial_cmp(
this: &Result<Value, Value>,
rhs: &Result<Value, Value>,
) -> VmResult<Option<Ordering>> {
match (this, rhs) {
(Ok(a), Ok(b)) => Value::partial_cmp(a, b),
(Err(a), Err(b)) => Value::partial_cmp(a, b),
(Ok(..), Err(..)) => VmResult::Ok(Some(Ordering::Greater)),
(Err(..), Ok(..)) => VmResult::Ok(Some(Ordering::Less)),
}
}
#[rune::function(keep, instance, protocol = CMP)]
#[inline]
fn cmp(this: &Result<Value, Value>, rhs: &Result<Value, Value>) -> VmResult<Ordering> {
match (this, rhs) {
(Ok(a), Ok(b)) => Value::cmp(a, b),
(Err(a), Err(b)) => Value::cmp(a, b),
(Ok(..), Err(..)) => VmResult::Ok(Ordering::Greater),
(Err(..), Ok(..)) => VmResult::Ok(Ordering::Less),
}
}
#[rune::function(keep, instance, protocol = HASH)]
fn hash(this: &Result<Value, Value>, hasher: &mut Hasher) -> VmResult<()> {
match this {
Ok(value) => {
hasher.write_u64(0);
vm_try!(value.hash(hasher));
}
Err(value) => {
hasher.write_u64(1);
vm_try!(value.hash(hasher));
}
}
VmResult::Ok(())
}
#[rune::function(keep, instance, protocol = DEBUG_FMT)]
#[inline]
fn debug_fmt(this: &Result<Value, Value>, f: &mut Formatter) -> VmResult<()> {
match this {
Ok(value) => {
vm_try!(f.try_write_str("Ok("));
vm_try!(value.debug_fmt(f));
vm_try!(f.try_write_str(")"));
}
Err(value) => {
vm_try!(f.try_write_str("Err("));
vm_try!(value.debug_fmt(f));
vm_try!(f.try_write_str(")"));
}
}
VmResult::Ok(())
}
#[rune::function(keep, instance, protocol = TRY)]
pub(crate) fn result_try(this: &Result<Value, Value>) -> VmResult<ControlFlow> {
VmResult::Ok(match this {
Ok(value) => ControlFlow::Continue(value.clone()),
Err(error) => ControlFlow::Break(vm_try!(Value::try_from(Err(error.clone())))),
})
}