Skip to content

Commit 6ac4b20

Browse files
committed
Introduce Interface helper to allow calling protocol functions
1 parent d841e5c commit 6ac4b20

15 files changed

+331
-48
lines changed

crates/runestick/src/call.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::{Future, Generator, Stream, Value, Vm, VmError};
12
use serde::{Deserialize, Serialize};
23
use std::fmt;
34

@@ -17,6 +18,19 @@ pub enum Call {
1718
Immediate,
1819
}
1920

21+
impl Call {
22+
/// Perform the call with the given virtual machine.
23+
#[inline]
24+
pub(crate) fn call_with_vm(self, vm: Vm) -> Result<Value, VmError> {
25+
Ok(match self {
26+
Call::Stream => Value::from(Stream::new(vm)),
27+
Call::Generator => Value::from(Generator::new(vm)),
28+
Call::Immediate => vm.complete()?,
29+
Call::Async => Value::from(Future::new(vm.async_complete())),
30+
})
31+
}
32+
}
33+
2034
impl fmt::Display for Call {
2135
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2236
match self {

crates/runestick/src/format.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ pub struct Format {
2727
pub(crate) spec: FormatSpec,
2828
}
2929

30+
impl Named for Format {
31+
const NAME: RawStr = RawStr::from_str("Format");
32+
}
33+
34+
impl FromValue for Format {
35+
fn from_value(value: Value) -> Result<Self, VmError> {
36+
Ok(*value.into_format()?)
37+
}
38+
}
39+
3040
/// A format specification.
3141
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
3242
#[non_exhaustive]
@@ -342,16 +352,6 @@ impl FormatSpec {
342352
}
343353
}
344354

345-
impl Named for Format {
346-
const NAME: RawStr = RawStr::from_str("Format");
347-
}
348-
349-
impl FromValue for Format {
350-
fn from_value(value: Value) -> Result<Self, VmError> {
351-
Ok(*value.into_format()?)
352-
}
353-
}
354-
355355
/// The type of formatting requested.
356356
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
357357
#[non_exhaustive]

crates/runestick/src/function.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::context::Handler;
22
use crate::VmErrorKind;
33
use crate::{
4-
Args, Call, ConstValue, Context, FromValue, Future, Generator, RawRef, Ref, Rtti, Shared,
5-
Stack, Stream, Tuple, Unit, UnsafeFromValue, Value, VariantRtti, Vm, VmCall, VmError, VmHalt,
4+
Args, Call, ConstValue, Context, FromValue, RawRef, Ref, Rtti, Shared, Stack, Tuple, Unit,
5+
UnsafeFromValue, Value, VariantRtti, Vm, VmCall, VmError, VmHalt,
66
};
77
use std::fmt;
88
use std::sync::Arc;
@@ -76,7 +76,8 @@ where
7676
pub(crate) fn call_with_vm(&self, vm: &mut Vm, args: usize) -> Result<Option<VmHalt>, VmError> {
7777
let reason = match &self.inner {
7878
Inner::FnHandler(handler) => {
79-
(handler.handler)(vm.stack_mut(), args)?;
79+
let _guard = crate::interface::EnvGuard::new(&vm.context, &vm.unit);
80+
(handler.handler)(&mut vm.stack, args)?;
8081
None
8182
}
8283
Inner::FnOffset(fn_offset) => {
@@ -346,12 +347,7 @@ impl FnOffset {
346347
args.into_stack(vm.stack_mut())?;
347348
extra.into_stack(vm.stack_mut())?;
348349

349-
Ok(match self.call {
350-
Call::Stream => Value::from(Stream::new(vm)),
351-
Call::Generator => Value::from(Generator::new(vm)),
352-
Call::Immediate => vm.complete()?,
353-
Call::Async => Value::from(Future::new(vm.async_complete())),
354-
})
350+
self.call.call_with_vm(vm)
355351
}
356352

357353
/// Perform a potentially optimized call into the specified vm.

crates/runestick/src/interface.rs

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use crate::{
2+
Args, Context, FromValue, Hash, IntoTypeHash, Iterator, Stack, Unit, UnitFn, Value, Vm,
3+
VmError, VmErrorKind,
4+
};
5+
use std::cell::Cell;
6+
use std::marker;
7+
use std::ptr;
8+
use std::sync::Arc;
9+
10+
thread_local! { static ENV: Cell<Env> = Cell::new(Env::null()) }
11+
12+
/// An interface which wraps a value and allows for accessing protocols.
13+
///
14+
/// This can be used as an argument type for native functions who wants to call
15+
/// a protocol function like [INTO_ITER](crate::INTO_ITER) (see
16+
/// [into_iter][Self::into_iter]).
17+
pub struct Interface {
18+
target: Value,
19+
unit: Arc<Unit>,
20+
context: Arc<Context>,
21+
}
22+
23+
impl Interface {
24+
/// Call the `into_iter` protocol on the value.
25+
pub fn into_iter(mut self) -> Result<Iterator, VmError> {
26+
let target = match std::mem::take(&mut self.target) {
27+
Value::Iterator(iterator) => return Ok(iterator.take()?),
28+
Value::Vec(vec) => return Ok(vec.borrow_ref()?.into_iterator()),
29+
Value::Object(object) => return Ok(object.borrow_ref()?.into_iterator()),
30+
target => target,
31+
};
32+
33+
let value = self.call_instance_fn(crate::INTO_ITER, target, ())?;
34+
Iterator::from_value(value)
35+
}
36+
37+
/// Helper function to call an instance function.
38+
fn call_instance_fn<H, A>(self, hash: H, target: Value, args: A) -> Result<Value, VmError>
39+
where
40+
H: IntoTypeHash,
41+
A: Args,
42+
{
43+
let count = args.count() + 1;
44+
let hash = Hash::instance_function(target.type_of()?, hash.into_type_hash());
45+
46+
if let Some(UnitFn::Offset {
47+
offset,
48+
args: expected,
49+
call,
50+
}) = self.unit.lookup(hash)
51+
{
52+
let mut vm = Vm::new(self.context.clone(), self.unit.clone());
53+
Self::check_args(count, expected)?;
54+
vm.stack.push(target);
55+
args.into_stack(&mut vm.stack)?;
56+
vm.set_ip(offset);
57+
return call.call_with_vm(vm);
58+
}
59+
60+
let handler = match self.context.lookup(hash) {
61+
Some(handler) => handler,
62+
None => return Err(VmError::from(VmErrorKind::MissingFunction { hash })),
63+
};
64+
65+
let mut stack = Stack::with_capacity(count);
66+
stack.push(target);
67+
args.into_stack(&mut stack)?;
68+
handler(&mut stack, count)?;
69+
Ok(stack.pop()?)
70+
}
71+
72+
/// Check that arguments matches expected or raise the appropriate error.
73+
fn check_args(args: usize, expected: usize) -> Result<(), VmError> {
74+
if args != expected {
75+
return Err(VmError::from(VmErrorKind::BadArgumentCount {
76+
actual: args,
77+
expected,
78+
}));
79+
}
80+
81+
Ok(())
82+
}
83+
}
84+
85+
impl FromValue for Interface {
86+
fn from_value(value: Value) -> Result<Self, VmError> {
87+
let env = ENV.with(|env| env.get());
88+
let Env { context, unit } = env;
89+
90+
if context.is_null() || unit.is_null() {
91+
return Err(VmError::from(VmErrorKind::MissingInterfaceEnvironment));
92+
}
93+
94+
// Safety: context and unit can only be registered publicly through
95+
// [EnvGuard], which makes sure that they are live for the duration of
96+
// the registration.
97+
Ok(Interface {
98+
target: value,
99+
context: unsafe { (*context).clone() },
100+
unit: unsafe { (*unit).clone() },
101+
})
102+
}
103+
}
104+
105+
pub(crate) struct EnvGuard<'a> {
106+
old: Env,
107+
_marker: marker::PhantomData<&'a ()>,
108+
}
109+
110+
impl<'a> EnvGuard<'a> {
111+
/// Construct a new environment guard with the given context and unit.
112+
pub(crate) fn new(context: &'a Arc<Context>, unit: &'a Arc<Unit>) -> EnvGuard<'a> {
113+
let old = ENV.with(|e| e.replace(Env { context, unit }));
114+
115+
EnvGuard {
116+
old,
117+
_marker: marker::PhantomData,
118+
}
119+
}
120+
}
121+
122+
impl Drop for EnvGuard<'_> {
123+
fn drop(&mut self) {
124+
ENV.with(|e| e.set(self.old));
125+
}
126+
}
127+
128+
#[derive(Debug, Clone, Copy)]
129+
struct Env {
130+
context: *const Arc<Context>,
131+
unit: *const Arc<Unit>,
132+
}
133+
134+
impl Env {
135+
const fn null() -> Self {
136+
Self {
137+
context: ptr::null(),
138+
unit: ptr::null(),
139+
}
140+
}
141+
}

crates/runestick/src/iterator.rs

+74-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use crate::{FromValue, Function, ToValue, Value, VmError};
1+
use crate::{
2+
FromValue, Function, Interface, Mut, Named, RawMut, RawRef, RawStr, Ref, ToValue,
3+
UnsafeFromValue, Value, VmError,
4+
};
5+
use std::fmt;
26
use std::iter;
37
use std::vec;
48

@@ -34,8 +38,6 @@ pub struct Iterator {
3438
inner: Inner,
3539
}
3640

37-
crate::__internal_impl_any!(Iterator);
38-
3941
impl Iterator {
4042
/// Construct a new owning iterator.
4143
///
@@ -108,13 +110,15 @@ impl Iterator {
108110
}
109111

110112
/// Chain this iterator with another.
111-
pub fn chain(self, other: Self) -> Self {
112-
Self {
113+
pub fn chain(self, other: Interface) -> Result<Self, VmError> {
114+
let other = other.into_iter()?;
115+
116+
Ok(Self {
113117
inner: Inner::Chain(Box::new(Chain {
114118
a: Some(self.inner),
115119
b: Some(other.inner),
116120
})),
117-
}
121+
})
118122
}
119123

120124
/// Map the iterator using the given function.
@@ -188,6 +192,50 @@ impl Iterator {
188192
}
189193
}
190194

195+
impl fmt::Debug for Iterator {
196+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197+
f.debug_tuple("Iterator").field(&self.inner).finish()
198+
}
199+
}
200+
201+
impl Named for Iterator {
202+
const NAME: RawStr = RawStr::from_str("Iterator");
203+
}
204+
205+
impl FromValue for Iterator {
206+
fn from_value(value: Value) -> Result<Self, VmError> {
207+
Ok(value.into_iterator()?.take()?)
208+
}
209+
}
210+
211+
impl<'a> UnsafeFromValue for &'a Iterator {
212+
type Output = *const Iterator;
213+
type Guard = RawRef;
214+
215+
fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
216+
let iterator = value.into_iterator()?;
217+
Ok(Ref::into_raw(iterator.into_ref()?))
218+
}
219+
220+
unsafe fn unsafe_coerce(output: Self::Output) -> Self {
221+
&*output
222+
}
223+
}
224+
225+
impl<'a> UnsafeFromValue for &'a mut Iterator {
226+
type Output = *mut Iterator;
227+
type Guard = RawMut;
228+
229+
fn from_value(value: Value) -> Result<(Self::Output, Self::Guard), VmError> {
230+
let iterator = value.into_iterator()?;
231+
Ok(Mut::into_raw(iterator.into_mut()?))
232+
}
233+
234+
unsafe fn unsafe_coerce(output: Self::Output) -> Self {
235+
&mut *output
236+
}
237+
}
238+
191239
enum Inner {
192240
Iterator(Box<IteratorObj<dyn IteratorTrait>>),
193241
DoubleEndedIterator(Box<IteratorObj<dyn DoubleEndedIteratorTrait>>),
@@ -294,6 +342,26 @@ impl Inner {
294342
}
295343
}
296344

345+
impl fmt::Debug for Inner {
346+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347+
match self {
348+
Inner::Iterator(iter) => write!(f, "{}", iter.name),
349+
Inner::DoubleEndedIterator(iter) => write!(f, "{}", iter.name),
350+
Inner::Map(inner) => f.debug_tuple("Map").field(&inner.inner).finish(),
351+
Inner::Filter(inner) => f.debug_tuple("Filter").field(&inner.inner).finish(),
352+
Inner::Rev(inner) => f.debug_tuple("Rev").field(inner).finish(),
353+
Inner::Chain(inner) => f
354+
.debug_tuple("Chain")
355+
.field(&inner.a)
356+
.field(&inner.b)
357+
.finish(),
358+
Inner::Enumerate(inner) => f.debug_tuple("Enumerate").field(&inner.inner).finish(),
359+
Inner::Take(inner) => f.debug_tuple("Take").field(&inner.inner).finish(),
360+
Inner::Peekable(inner) => f.debug_tuple("Peekable").field(&inner.inner).finish(),
361+
}
362+
}
363+
}
364+
297365
struct Map {
298366
inner: Inner,
299367
map: Function,

crates/runestick/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ mod guarded_args;
7474
mod hash;
7575
mod id;
7676
mod inst;
77+
mod interface;
7778
mod item;
7879
mod iterator;
7980
mod label;
@@ -154,6 +155,7 @@ pub use self::generator::Generator;
154155
pub use self::generator_state::GeneratorState;
155156
pub use self::guarded_args::GuardedArgs;
156157
pub use self::id::Id;
158+
pub use self::interface::Interface;
157159
pub use self::iterator::Iterator;
158160
pub use self::label::{DebugLabel, Label};
159161
pub use self::module::{InstFnNameHash, Module};
@@ -166,8 +168,9 @@ pub use self::spanned_error::{SpannedError, WithSpan};
166168
pub use self::static_string::StaticString;
167169
pub use self::static_type::{
168170
StaticType, BOOL_TYPE, BYTES_TYPE, BYTE_TYPE, CHAR_TYPE, FLOAT_TYPE, FORMAT_TYPE,
169-
FUNCTION_TYPE, FUTURE_TYPE, GENERATOR_STATE_TYPE, GENERATOR_TYPE, INTEGER_TYPE, OBJECT_TYPE,
170-
OPTION_TYPE, RESULT_TYPE, STREAM_TYPE, STRING_TYPE, TUPLE_TYPE, UNIT_TYPE, VEC_TYPE,
171+
FUNCTION_TYPE, FUTURE_TYPE, GENERATOR_STATE_TYPE, GENERATOR_TYPE, INTEGER_TYPE, INTERFACE_TYPE,
172+
ITERATOR_TYPE, OBJECT_TYPE, OPTION_TYPE, RESULT_TYPE, STREAM_TYPE, STRING_TYPE, TUPLE_TYPE,
173+
UNIT_TYPE, VEC_TYPE,
171174
};
172175
pub use self::stream::Stream;
173176
pub use self::to_value::{ToValue, UnsafeToValue};

crates/runestick/src/modules/object.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,11 @@ pub fn module() -> Result<Module, ContextError> {
1414
module.inst_fn("contains_key", contains_key)?;
1515
module.inst_fn("get", get)?;
1616

17-
module.inst_fn("iter", object_iter)?;
18-
module.inst_fn(crate::INTO_ITER, object_iter)?;
17+
module.inst_fn("iter", Object::into_iterator)?;
18+
module.inst_fn(crate::INTO_ITER, Object::into_iterator)?;
1919
Ok(module)
2020
}
2121

22-
fn object_iter(object: &Object) -> crate::Iterator {
23-
crate::Iterator::from("std::object::Iter", object.clone().into_iter())
24-
}
25-
2622
fn contains_key(object: &Object, key: &str) -> bool {
2723
object.contains_key(key)
2824
}

0 commit comments

Comments
 (0)