Skip to content

Commit

Permalink
Merge pull request #123 from schungx/master
Browse files Browse the repository at this point in the history
Send+Sync
  • Loading branch information
schungx authored Apr 5, 2020
2 parents d614d5d + 2bb195c commit 66a4956
Show file tree
Hide file tree
Showing 24 changed files with 1,793 additions and 715 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ keywords = [ "scripting" ]
categories = [ "no-std", "embedded", "parser-implementations" ]

[dependencies]
num-traits = "0.2.11"
num-traits = "*"

[features]
#default = ["no_function", "no_index", "no_object", "no_float", "only_i32", "no_stdlib", "unchecked", "no_optimize"]
#default = ["no_function", "no_index", "no_object", "no_float", "only_i32", "no_stdlib", "unchecked", "no_optimize", "sync"]
default = []
unchecked = [] # unchecked arithmetic
no_stdlib = [] # no standard library of utility functions
Expand All @@ -32,6 +32,7 @@ no_optimize = [] # no script optimizer
optimize_full = [] # set optimization level to Full (default is Simple) - this is a feature used only to simplify testing
only_i32 = [] # set INT=i32 (useful for 32-bit systems)
only_i64 = [] # set INT=i64 (default) and disable support for all other integer types
sync = [] # restrict to only types that implement Send + Sync

# compiling for no-std
no_std = [ "num-traits/libm", "hashbrown", "core-error", "libm" ]
Expand Down
378 changes: 267 additions & 111 deletions README.md

Large diffs are not rendered by default.

55 changes: 29 additions & 26 deletions examples/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ use std::{
};

fn print_error(input: &str, err: EvalAltResult) {
fn padding(pad: &str, len: usize) -> String {
iter::repeat(pad).take(len).collect::<String>()
}

let lines: Vec<_> = input.trim().split('\n').collect();

let line_no = if lines.len() > 1 {
Expand Down Expand Up @@ -54,8 +50,9 @@ fn print_error(input: &str, err: EvalAltResult) {
};

println!(
"{}^ {}",
padding(" ", line_no.len() + p.position().unwrap() - 1),
"{0:>1$} {2}",
"^",
line_no.len() + p.position().unwrap(),
err_text.replace(&pos_text, "")
);
}
Expand All @@ -80,8 +77,9 @@ fn main() {
let mut scope = Scope::new();

let mut input = String::new();
let mut ast_u: Option<AST> = None;
let mut ast: Option<AST> = None;
let mut main_ast = AST::new();
let mut ast_u = AST::new();
let mut ast = AST::new();

println!("Rhai REPL tool");
println!("==============");
Expand Down Expand Up @@ -115,6 +113,10 @@ fn main() {

let script = input.trim();

if script.is_empty() {
continue;
}

// Implement standard commands
match script {
"help" => {
Expand All @@ -123,21 +125,13 @@ fn main() {
}
"exit" | "quit" => break, // quit
"astu" => {
if matches!(&ast_u, Some(_)) {
// print the last un-optimized AST
println!("{:#?}", ast_u.as_ref().unwrap());
} else {
println!("()");
}
// print the last un-optimized AST
println!("{:#?}", &ast_u);
continue;
}
"ast" => {
if matches!(&ast, Some(_)) {
// print the last AST
println!("{:#?}", ast.as_ref().unwrap());
} else {
println!("()");
}
// print the last AST
println!("{:#?}", &ast);
continue;
}
_ => (),
Expand All @@ -147,26 +141,35 @@ fn main() {
.compile_with_scope(&scope, &script)
.map_err(EvalAltResult::ErrorParsing)
.and_then(|r| {
ast_u = Some(r);
ast_u = r.clone();

#[cfg(not(feature = "no_optimize"))]
{
engine.set_optimization_level(OptimizationLevel::Full);
ast = Some(engine.optimize_ast(&scope, ast_u.as_ref().unwrap()));
ast = engine.optimize_ast(&scope, r);
engine.set_optimization_level(OptimizationLevel::None);
}

#[cfg(feature = "no_optimize")]
{
ast = ast_u.clone();
ast = r;
}

engine
.consume_ast_with_scope(&mut scope, true, ast.as_ref().unwrap())
// Merge the AST into the main
main_ast = main_ast.merge(&ast);

// Evaluate
let result = engine
.consume_ast_with_scope(&mut scope, &main_ast)
.or_else(|err| match err {
EvalAltResult::Return(_, _) => Ok(()),
err => Err(err),
})
});

// Throw away all the statements, leaving only the functions
main_ast.retain_functions();

result
})
{
println!();
Expand Down
15 changes: 6 additions & 9 deletions examples/rhai_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@ use rhai::OptimizationLevel;

use std::{env, fs::File, io::Read, iter, process::exit};

fn padding(pad: &str, len: usize) -> String {
iter::repeat(pad).take(len).collect::<String>()
}

fn eprint_error(input: &str, err: EvalAltResult) {
fn eprint_line(lines: &[&str], line: usize, pos: usize, err: &str) {
let line_no = format!("{}: ", line);
let pos_text = format!(" (line {}, position {})", line, pos);

eprintln!("{}{}", line_no, lines[line - 1]);
eprintln!(
"{}^ {}",
padding(" ", line_no.len() + pos - 1),
"{:>1$} {2}",
"^",
line_no.len() + pos,
err.replace(&pos_text, "")
);
eprintln!("");
Expand Down Expand Up @@ -75,10 +72,10 @@ fn main() {
exit(1);
}

if let Err(err) = engine.consume(false, &contents) {
eprintln!("{}", padding("=", filename.len()));
if let Err(err) = engine.consume(&contents) {
eprintln!("{:=<1$}", "", filename.len());
eprintln!("{}", filename);
eprintln!("{}", padding("=", filename.len()));
eprintln!("{:=<1$}", "", filename.len());
eprintln!("");

eprint_error(&contents, err);
Expand Down
99 changes: 84 additions & 15 deletions src/any.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
use crate::stdlib::{
any::{type_name, Any as StdAny, TypeId},
any::{type_name, TypeId},
boxed::Box,
fmt,
};

/// An raw value of any type.
///
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
pub type Variant = dyn Any;

/// A boxed dynamic type containing any value.
///
/// Currently, `Dynamic` is not `Send` nor `Sync`, so it can practically be any type.
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
pub type Dynamic = Box<Variant>;

/// A trait covering any type.
pub trait Any: StdAny {
#[cfg(feature = "sync")]
pub trait Any: crate::stdlib::any::Any + Send + Sync {
/// Get the `TypeId` of this type.
fn type_id(&self) -> TypeId;

Expand All @@ -28,7 +35,44 @@ pub trait Any: StdAny {
fn _closed(&self) -> _Private;
}

impl<T: Clone + StdAny + ?Sized> Any for T {
#[cfg(feature = "sync")]
impl<T: crate::stdlib::any::Any + Clone + Send + Sync + ?Sized> Any for T {
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}

fn type_name(&self) -> &'static str {
type_name::<T>()
}

fn into_dynamic(&self) -> Dynamic {
Box::new(self.clone())
}

fn _closed(&self) -> _Private {
_Private
}
}

/// A trait covering any type.
#[cfg(not(feature = "sync"))]
pub trait Any: crate::stdlib::any::Any {
/// Get the `TypeId` of this type.
fn type_id(&self) -> TypeId;

/// Get the name of this type.
fn type_name(&self) -> &'static str;

/// Convert into `Dynamic`.
fn into_dynamic(&self) -> Dynamic;

/// This trait may only be implemented by `rhai`.
#[doc(hidden)]
fn _closed(&self) -> _Private;
}

#[cfg(not(feature = "sync"))]
impl<T: crate::stdlib::any::Any + Clone + ?Sized> Any for T {
fn type_id(&self) -> TypeId {
TypeId::of::<T>()
}
Expand All @@ -48,15 +92,13 @@ impl<T: Clone + StdAny + ?Sized> Any for T {

impl Variant {
/// Is this `Variant` a specific type?
pub(crate) fn is<T: Any>(&self) -> bool {
let t = TypeId::of::<T>();
let boxed = <Variant as Any>::type_id(self);

t == boxed
pub fn is<T: Any>(&self) -> bool {
TypeId::of::<T>() == <Variant as Any>::type_id(self)
}

/// Get a reference of a specific type to the `Variant`.
pub(crate) fn downcast_ref<T: Any>(&self) -> Option<&T> {
/// Returns `None` if the cast fails.
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe { Some(&*(self as *const Variant as *const T)) }
} else {
Expand All @@ -65,7 +107,8 @@ impl Variant {
}

/// Get a mutable reference of a specific type to the `Variant`.
pub(crate) fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
/// Returns `None` if the cast fails.
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe { Some(&mut *(self as *mut Variant as *mut T)) }
} else {
Expand All @@ -82,14 +125,21 @@ impl fmt::Debug for Variant {

impl Clone for Dynamic {
fn clone(&self) -> Self {
Any::into_dynamic(self.as_ref())
self.as_ref().into_dynamic()
}
}

/// An extension trait that allows down-casting a `Dynamic` value to a specific type.
pub trait AnyExt: Sized {
/// Get a copy of a `Dynamic` value as a specific type.
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self>;
fn try_cast<T: Any + Clone>(self) -> Result<T, Self>;

/// Get a copy of a `Dynamic` value as a specific type.
///
/// # Panics
///
/// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
fn cast<T: Any + Clone>(self) -> T;

/// This trait may only be implemented by `rhai`.
#[doc(hidden)]
Expand All @@ -106,19 +156,38 @@ impl AnyExt for Dynamic {
///
/// let x: Dynamic = 42_u32.into_dynamic();
///
/// assert_eq!(*x.downcast::<u32>().unwrap(), 42);
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
/// ```
fn downcast<T: Any + Clone>(self) -> Result<Box<T>, Self> {
fn try_cast<T: Any + Clone>(self) -> Result<T, Self> {
if self.is::<T>() {
unsafe {
let raw: *mut Variant = Box::into_raw(self);
Ok(Box::from_raw(raw as *mut T))
Ok(*Box::from_raw(raw as *mut T))
}
} else {
Err(self)
}
}

/// Get a copy of the `Dynamic` value as a specific type.
///
/// # Panics
///
/// Panics if the cast fails (e.g. the type of the actual value is not the same as the specified type).
///
/// # Example
///
/// ```
/// use rhai::{Dynamic, Any, AnyExt};
///
/// let x: Dynamic = 42_u32.into_dynamic();
///
/// assert_eq!(x.cast::<u32>(), 42);
/// ```
fn cast<T: Any + Clone>(self) -> T {
self.try_cast::<T>().expect("cast failed")
}

fn _closed(&self) -> _Private {
_Private
}
Expand Down
Loading

0 comments on commit 66a4956

Please sign in to comment.