From d756b7bac62db96a034c869f36ae88e81c2c5aa4 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 11:39:00 +0800 Subject: [PATCH 01/10] Rename FnWrongDefinition to WrongFnDefinition. --- CHANGELOG.md | 1 + src/fn_call.rs | 2 +- src/parse_error.rs | 4 ++-- src/parser.rs | 2 +- src/token.rs | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4bbbc5..7608ccc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ Breaking changes * Shebangs at the very beginning of script files are skipped when loading them. * [`smartstring`](https://crates.io/crates/smartstring) is used for identifiers by default. Currently, a PR branch is pulled because it breaks on `no-std` builds. The official crate will be used once `smartstring` is fixed to support `no-std`. * `Map` is now an alias to `BTreeMap` instead of `HashMap` because most object maps hold few properties. +* `EvalAltResult::FnWrongDefinition` is renamed `WrongFnDefinition` for consistency. New features ------------ diff --git a/src/fn_call.rs b/src/fn_call.rs index e7cef8ca..f323632b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -866,7 +866,7 @@ impl Engine { // If new functions are defined within the eval string, it is an error if ast.lib().count().0 != 0 { - return Err(ParseErrorType::FnWrongDefinition.into()); + return Err(ParseErrorType::WrongFnDefinition.into()); } // Evaluate the AST diff --git a/src/parse_error.rs b/src/parse_error.rs index b31608b6..a0a62e00 100644 --- a/src/parse_error.rs +++ b/src/parse_error.rs @@ -132,7 +132,7 @@ pub enum ParseErrorType { /// Defining a function `fn` in an appropriate place (e.g. inside another function). /// /// Never appears under the `no_function` feature. - FnWrongDefinition, + WrongFnDefinition, /// Defining a function with a name that conflicts with an existing function. /// Wrapped values are the function name and number of parameters. /// @@ -199,7 +199,7 @@ impl ParseErrorType { Self::VariableExpected => "Expecting name of a variable", Self::Reserved(_) => "Invalid use of reserved keyword", Self::ExprExpected(_) => "Expecting an expression", - Self::FnWrongDefinition => "Function definitions must be at global level and cannot be inside a block or another function", + Self::WrongFnDefinition => "Function definitions must be at global level and cannot be inside a block or another function", Self::FnDuplicatedDefinition(_, _) => "Function already exists", Self::FnMissingName => "Expecting function name in function declaration", Self::FnMissingParams(_) => "Expecting parameters in function declaration", diff --git a/src/parser.rs b/src/parser.rs index 083bd996..49c1d57d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2481,7 +2481,7 @@ fn parse_stmt( // fn ... #[cfg(not(feature = "no_function"))] - Token::Fn if !settings.is_global => Err(PERR::FnWrongDefinition.into_err(settings.pos)), + Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(settings.pos)), #[cfg(not(feature = "no_function"))] Token::Fn | Token::Private => { diff --git a/src/token.rs b/src/token.rs index ecd4d661..c5498416 100644 --- a/src/token.rs +++ b/src/token.rs @@ -875,7 +875,7 @@ pub fn parse_string_literal( match next_char { // \r - ignore if followed by \n - '\r' if stream.peek_next().unwrap_or('\0') == '\n' => {} + '\r' if stream.peek_next().map(|ch| ch == '\n').unwrap_or(false) => {} // \... '\\' if escape.is_empty() && !verbatim => { escape.push('\\'); From e36e490a30fe7e08e8064445d6822d9b0c31a4cc Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 13:59:27 +0800 Subject: [PATCH 02/10] Support back-tick at EOL for literal strings. --- src/parser.rs | 4 ++-- src/token.rs | 37 +++++++++++++++++++++++++++++-------- tests/string.rs | 12 ++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 49c1d57d..4460539d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -715,13 +715,13 @@ fn parse_map_literal( return Err(PERR::Reserved(s).into_err(pos)); } (Token::LexError(err), pos) => return Err(err.into_err(pos)), - (_, pos) if map.is_empty() => { + (Token::EOF, pos) => { return Err( PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into()) .into_err(pos), ); } - (Token::EOF, pos) => { + (_, pos) if map.is_empty() => { return Err( PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into()) .into_err(pos), diff --git a/src/token.rs b/src/token.rs index c5498416..0aea77b5 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1294,15 +1294,36 @@ fn get_next_token_inner( return get_identifier(stream, pos, start_pos, c); } - // " or ` - string literal - ('"', _) | ('`', _) => { - let multi_line = c == '`'; + // " - string literal + ('"', _) => { + return parse_string_literal(stream, state, pos, c, true, false).map_or_else( + |err| Some((Token::LexError(err.0), err.1)), + |out| Some((Token::StringConstant(out), start_pos)), + ); + } + // ` - string literal + ('`', _) => { + // Start from the next line if ` at the end of line + match stream.peek_next() { + // `\r - start from next line + Some('\r') => { + eat_next(stream, pos); + // `\r\n + if stream.peek_next().map(|ch| ch == '\n').unwrap_or(false) { + eat_next(stream, pos); + } + } + // `\n - start from next line + Some('\n') => { + eat_next(stream, pos); + } + _ => (), + } - return parse_string_literal(stream, state, pos, c, !multi_line, multi_line) - .map_or_else( - |err| Some((Token::LexError(err.0), err.1)), - |out| Some((Token::StringConstant(out), start_pos)), - ); + return parse_string_literal(stream, state, pos, c, false, true).map_or_else( + |err| Some((Token::LexError(err.0), err.1)), + |out| Some((Token::StringConstant(out), start_pos)), + ); } // ' - character literal diff --git a/tests/string.rs b/tests/string.rs index d6885a34..2e2d74a7 100644 --- a/tests/string.rs +++ b/tests/string.rs @@ -8,6 +8,10 @@ fn test_string() -> Result<(), Box> { engine.eval::(r#""Test string: \u2764""#)?, "Test string: ❤" ); + assert_eq!( + engine.eval::("\"Test\rstring: \\u2764\"")?, + "Test\rstring: ❤" + ); assert_eq!( engine.eval::(" \"Test string: \\u2764\\\n hello, world!\"")?, "Test string: ❤ hello, world!" @@ -16,6 +20,14 @@ fn test_string() -> Result<(), Box> { engine.eval::(" `Test string: \\u2764\nhello,\\nworld!`")?, "Test string: \\u2764\nhello,\\nworld!" ); + assert_eq!( + engine.eval::(" `\nTest string: \\u2764\nhello,\\nworld!`")?, + "Test string: \\u2764\nhello,\\nworld!" + ); + assert_eq!( + engine.eval::(" `\r\nTest string: \\u2764\nhello,\\nworld!`")?, + "Test string: \\u2764\nhello,\\nworld!" + ); assert_eq!( engine.eval::(r#""Test string: \x58""#)?, "Test string: X" From ec7b906f7153331bb03738376f43e7ae4d50aa46 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 18:06:58 +0800 Subject: [PATCH 03/10] Patah smartstring for no-std. --- Cargo.toml | 6 ++---- no_std/no_std_test/Cargo.toml | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4c1d6c4e..996ec7b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,11 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"] smallvec = { version = "1.6", default-features = false, features = ["union"] } ahash = { version = "0.7", default-features = false } num-traits = { version = "0.2", default_features = false } -#smartstring = { version = "0.2.6" } -smartstring = { git = "https://github.com/okready/smartstring", branch = "fix-no_std-builds", default_features = false } +smartstring = { version = "0.2.6", default_features = false } rhai_codegen = { version = "0.3.4", path = "codegen", features = ["metadata"] } [features] -default = [] +default = ["smartstring/std"] # remove 'smartstring/std' when smartstring is updated to support no-std unchecked = [] # unchecked arithmetic sync = [] # restrict to only types that implement Send + Sync no_optimize = [] # no script optimizer @@ -42,7 +41,6 @@ internals = [] # expose internal data structures unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers. metadata = ["serde_json"] # enable exporting functions metadata -no_smartstring = [] # set Identifier=ImmutableString no_std = ["smallvec/union", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] # compiling for WASM diff --git a/no_std/no_std_test/Cargo.toml b/no_std/no_std_test/Cargo.toml index ec38bcc0..5ae73ab8 100644 --- a/no_std/no_std_test/Cargo.toml +++ b/no_std/no_std_test/Cargo.toml @@ -12,7 +12,7 @@ homepage = "https://github.com/rhaiscript/rhai/tree/no_std/no_std_test" repository = "https://github.com/rhaiscript/rhai" [dependencies] -rhai = { path = "../../", features = [ "no_std" ] } +rhai = { path = "../../", features = [ "no_std" ], default_features = false } wee_alloc = { version = "0.4.5", default_features = false } [profile.dev] @@ -36,3 +36,7 @@ inherits = "release" [profile.macos] inherits = "release" lto = "fat" + +[patch.crates-io] +# Patch smartstring wth a PR fix because it doesn't properly handle no-std builds. +smartstring = { git = "https://github.com/okready/smartstring", branch = "fix-no_std-builds" } From b14d18934af8909e25e8e9c1b06bffedd97e8044 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 18:57:16 +0800 Subject: [PATCH 04/10] Add Dynamic::clone_cast. --- CHANGELOG.md | 1 + src/dynamic.rs | 31 +++++++++++++++++++++++++++++++ src/module/mod.rs | 2 +- src/serde/de.rs | 40 ++++++++++++++++++++-------------------- tests/arrays.rs | 5 +++++ tests/closures.rs | 2 +- tests/maps.rs | 22 +++++++++++----------- 7 files changed, 70 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7608ccc3..d0421301 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Enhancements * Replaced all `HashMap` usage with `BTreeMap` for better performance because collections in Rhai are tiny. * `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any clonable type. * `#[rhai_fn(return_raw)]` can now return `Result>` where `T` is any clonable type instead of `Result>`. +* `Dynamic::clone_cast` is added to simplify casting from a `&Dynamic`. Version 0.19.14 diff --git a/src/dynamic.rs b/src/dynamic.rs index fd730ef3..3c0c23d4 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -1131,6 +1131,37 @@ impl Dynamic { ) }) } + /// Clone the [`Dynamic`] value and convert it into a specific type. + /// + /// Casting to a [`Dynamic`] just returns as is, but if it contains a shared value, + /// it is cloned into a [`Dynamic`] with a normal value. + /// + /// Returns [`None`] if types mismatched. + /// + /// # Panics or Deadlocks + /// + /// Panics if the cast fails (e.g. the type of the actual value is not the + /// same as the specified type). + /// + /// Under the `sync` feature, this call may deadlock, or [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1). + /// Otherwise, this call panics if the data is currently borrowed for write. + /// + /// These normally shouldn't occur since most operations in Rhai is single-threaded. + /// + /// # Example + /// + /// ``` + /// use rhai::Dynamic; + /// + /// let x = Dynamic::from(42_u32); + /// let y = &x; + /// + /// assert_eq!(y.clone_cast::(), 42); + /// ``` + #[inline(always)] + pub fn clone_cast(&self) -> T { + self.read_lock::().unwrap().clone() + } /// Flatten the [`Dynamic`] and clone it. /// /// If the [`Dynamic`] is not a shared value, it returns a cloned copy. diff --git a/src/module/mod.rs b/src/module/mod.rs index 824d4e72..8ae91968 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -768,7 +768,7 @@ impl Module { /// // Get the second parameter by 'consuming' it /// let double = std::mem::take(args[1]).cast::(); /// // Since it is a primary type, it can also be cheaply copied - /// let double = args[1].clone().cast::(); + /// let double = args[1].clone_cast::(); /// // Get a mutable reference to the first argument. /// let mut x = args[0].write_lock::().unwrap(); /// diff --git a/src/serde/de.rs b/src/serde/de.rs index 802a47e2..faf98d71 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -183,7 +183,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x)) } } @@ -193,7 +193,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x)) } } @@ -205,7 +205,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x)) } } @@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x)) } } @@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x)) } } @@ -239,7 +239,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x)) } } @@ -249,7 +249,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x)) } } @@ -259,7 +259,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x)) } } @@ -269,7 +269,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x)) } } @@ -279,7 +279,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x)) } } @@ -288,7 +288,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_float"))] return self .value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x)); #[cfg(feature = "no_float")] @@ -298,7 +298,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { return self .value - .downcast_ref::() + .downclone_cast::() .and_then(|&x| x.to_f32()) .map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v)); } @@ -312,7 +312,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_float"))] return self .value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x)); #[cfg(feature = "no_float")] @@ -322,7 +322,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { return self .value - .downcast_ref::() + .downclone_cast::() .and_then(|&x| x.to_f64()) .map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v)); } @@ -334,12 +334,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_char>(self, visitor: V) -> Result> { self.value - .downcast_ref::() + .downclone_cast::() .map_or_else(|| self.type_error(), |&x| visitor.visit_char(x)) } fn deserialize_str>(self, visitor: V) -> Result> { - self.value.downcast_ref::().map_or_else( + self.value.downclone_cast::().map_or_else( || self.type_error(), |x| visitor.visit_borrowed_str(x.as_str()), ) @@ -366,7 +366,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_unit>(self, visitor: V) -> Result> { self.value - .downcast_ref::<()>() + .downclone_cast::<()>() .map_or_else(|| self.type_error(), |_| visitor.visit_unit()) } @@ -388,7 +388,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_seq>(self, _visitor: V) -> Result> { #[cfg(not(feature = "no_index"))] - return self.value.downcast_ref::().map_or_else( + return self.value.downclone_cast::().map_or_else( || self.type_error(), |arr| _visitor.visit_seq(IterateArray::new(arr.iter())), ); @@ -416,7 +416,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_map>(self, _visitor: V) -> Result> { #[cfg(not(feature = "no_object"))] - return self.value.downcast_ref::().map_or_else( + return self.value.downclone_cast::().map_or_else( || self.type_error(), |map| { _visitor.visit_map(IterateMap::new( @@ -449,7 +449,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { visitor.visit_enum(s.as_str().into_deserializer()) } else { #[cfg(not(feature = "no_object"))] - if let Some(map) = self.value.downcast_ref::() { + if let Some(map) = self.value.downclone_cast::() { let mut iter = map.iter(); let first = iter.next(); let second = iter.next(); diff --git a/tests/arrays.rs b/tests/arrays.rs index 1be7f8cb..0c154cd6 100644 --- a/tests/arrays.rs +++ b/tests/arrays.rs @@ -59,6 +59,11 @@ fn test_arrays() -> Result<(), Box> { 5 ); + let mut a = Array::new(); + a.push((42 as INT).into()); + + assert_eq!(a[0].clone_cast::(), 42); + Ok(()) } diff --git a/tests/closures.rs b/tests/closures.rs index cfa1f355..4b35e2d7 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -299,7 +299,7 @@ fn test_closures_shared_obj() -> Result<(), Box> { // Make closure let f = move |p1: TestStruct, p2: TestStruct| -> Result<(), Box> { - let action_ptr = res["action"].clone().cast::(); + let action_ptr = res["action"].clone_cast::(); let name = action_ptr.fn_name(); engine.call_fn(&mut Scope::new(), &ast, name, (p1, p2)) }; diff --git a/tests/maps.rs b/tests/maps.rs index 5892c29d..895c7310 100644 --- a/tests/maps.rs +++ b/tests/maps.rs @@ -94,9 +94,9 @@ fn test_map_assign() -> Result<(), Box> { let x = engine.eval::(r#"let x = #{a: 1, b: true, "c$": "hello"}; x"#)?; - assert_eq!(x["a"].clone().cast::(), 1); - assert_eq!(x["b"].clone().cast::(), true); - assert_eq!(x["c$"].clone().cast::(), "hello"); + assert_eq!(x["a"].clone_cast::(), 1); + assert_eq!(x["b"].clone_cast::(), true); + assert_eq!(x["c$"].clone_cast::(), "hello"); Ok(()) } @@ -107,9 +107,9 @@ fn test_map_return() -> Result<(), Box> { let x = engine.eval::(r#"#{a: 1, b: true, "c$": "hello"}"#)?; - assert_eq!(x["a"].clone().cast::(), 1); - assert_eq!(x["b"].clone().cast::(), true); - assert_eq!(x["c$"].clone().cast::(), "hello"); + assert_eq!(x["a"].clone_cast::(), 1); + assert_eq!(x["b"].clone_cast::(), true); + assert_eq!(x["c$"].clone_cast::(), "hello"); Ok(()) } @@ -152,11 +152,11 @@ fn test_map_json() -> Result<(), Box> { assert!(!map.contains_key("x")); - assert_eq!(map["a"].clone().cast::(), 1); - assert_eq!(map["b"].clone().cast::(), true); - assert_eq!(map["c"].clone().cast::(), 42); - assert_eq!(map["$d e f!"].clone().cast::(), "hello"); - assert_eq!(map["z"].clone().cast::<()>(), ()); + assert_eq!(map["a"].clone_cast::(), 1); + assert_eq!(map["b"].clone_cast::(), true); + assert_eq!(map["c"].clone_cast::(), 42); + assert_eq!(map["$d e f!"].clone_cast::(), "hello"); + assert_eq!(map["z"].clone_cast::<()>(), ()); #[cfg(not(feature = "no_index"))] { From 04625fb752560c7eceed976568f710ecb695b6e2 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 21:33:30 +0800 Subject: [PATCH 05/10] Add literal string and continuation example. --- scripts/string.rhai | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/scripts/string.rhai b/scripts/string.rhai index 70ea201e..0bb799c5 100644 --- a/scripts/string.rhai +++ b/scripts/string.rhai @@ -2,8 +2,8 @@ print("hello"); print("this\nis \\ nice"); // escape sequences -print("40 hex is \x40"); // hex escape sequence -print("unicode fun: \u2764"); // Unicode escape sequence +print("0x40 hex is \x40"); // hex escape sequence +print("Unicode fun: \u2764"); // Unicode escape sequence print("more fun: \U0001F603"); // Unicode escape sequence print("foo" + " " + "bar"); // string building using strings print("foo" < "bar"); // string comparison @@ -15,3 +15,22 @@ print("length=" + s.len); // should be 17 s[s.len-3] = '?'; // change the string print("Question: " + s); // should print 'Question: hello, world?' + +// Line continuation: +let s = "This is a long \ + string constructed using \ + line continuation"; + +print("One string: " + s); + +// Multi-line literal string: +let s = ` + \U0001F603 This is a multi-line + "string" with \t\x20\r\n +made using multi-line literal + string syntax. +`; + +print(s); + +print(">>> END <<<"); From 6eb6e07d57400f9a596ba1cfe42e6e847f6bdc19 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 22:30:02 +0800 Subject: [PATCH 06/10] Remove metadata from codegen dependency. --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 996ec7b8..cf75cb52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,10 @@ smallvec = { version = "1.6", default-features = false, features = ["union"] } ahash = { version = "0.7", default-features = false } num-traits = { version = "0.2", default_features = false } smartstring = { version = "0.2.6", default_features = false } -rhai_codegen = { version = "0.3.4", path = "codegen", features = ["metadata"] } +rhai_codegen = { version = "0.3.4", path = "codegen", default_features = false } [features] -default = ["smartstring/std"] # remove 'smartstring/std' when smartstring is updated to support no-std +default = ["smartstring/std", "ahash/std", "num-traits/std"] # remove 'smartstring/std' when smartstring is updated to support no-std unchecked = [] # unchecked arithmetic sync = [] # restrict to only types that implement Send + Sync no_optimize = [] # no script optimizer @@ -39,9 +39,9 @@ no_closure = [] # no automatic sharing and capture of anonymous no_module = [] # no modules internals = [] # expose internal data structures unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers. -metadata = ["serde_json"] # enable exporting functions metadata +metadata = ["serde_json", "rhai_codegen/metadata"] # enable exporting functions metadata -no_std = ["smallvec/union", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] +no_std = ["num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"] # compiling for WASM wasm-bindgen = ["instant/wasm-bindgen"] From a049f7b5ba9a06d338a90653ce3ad9ef41edada9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 30 Mar 2021 23:55:29 +0800 Subject: [PATCH 07/10] Optimize data structures. --- src/ast.rs | 18 +++++++++++------- src/engine.rs | 14 ++++++++------ src/optimize.rs | 4 ++-- src/parser.rs | 43 +++++++++++++++++++++++++------------------ 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index ca012df1..408db58e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -864,19 +864,23 @@ pub enum Stmt { /// `if` expr `{` stmt `}` `else` `{` stmt `}` If(Expr, Box<(StmtBlock, StmtBlock)>, Position), /// `switch` expr `{` literal or _ `=>` stmt `,` ... `}` - Switch(Expr, Box<(BTreeMap, StmtBlock)>, Position), + Switch( + Expr, + Box<(BTreeMap>, StmtBlock)>, + Position, + ), /// `while` expr `{` stmt `}` While(Expr, Box, Position), /// `do` `{` stmt `}` `while`|`until` expr Do(Box, Expr, bool, Position), /// `for` id `in` expr `{` stmt `}` - For(Expr, Box<(Identifier, StmtBlock)>, Position), + For(Expr, Box<(Ident, StmtBlock)>, Position), /// \[`export`\] `let` id `=` expr Let(Expr, Box, bool, Position), /// \[`export`\] `const` id `=` expr Const(Expr, Box, bool, Position), /// expr op`=` expr - Assignment(Box<(Expr, Expr, Option)>, Position), + Assignment(Box<(Expr, Option, Expr)>, Position), /// `{` stmt`;` ... `}` Block(Vec, Position), /// `try` `{` stmt; ... `}` `catch` `(` var `)` `{` stmt; ... `}` @@ -901,7 +905,7 @@ pub enum Stmt { Export(Vec<(Ident, Option)>, Position), /// Convert a variable to shared. #[cfg(not(feature = "no_closure"))] - Share(Box), + Share(Identifier), } impl Default for Stmt { @@ -967,7 +971,7 @@ impl Stmt { Self::Export(_, pos) => *pos, #[cfg(not(feature = "no_closure"))] - Self::Share(x) => x.pos, + Self::Share(_) => Position::NONE, } } /// Override the [position][Position] of this statement. @@ -998,7 +1002,7 @@ impl Stmt { Self::Export(_, pos) => *pos = new_pos, #[cfg(not(feature = "no_closure"))] - Self::Share(x) => x.pos = new_pos, + Self::Share(_) => (), } self @@ -1203,7 +1207,7 @@ impl Stmt { if !x.0.walk(path, on_node) { return false; } - if !x.1.walk(path, on_node) { + if !x.2.walk(path, on_node) { return false; } } diff --git a/src/engine.rs b/src/engine.rs index 16f32037..05c64223 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1957,7 +1957,7 @@ impl Engine { // var op= rhs Stmt::Assignment(x, op_pos) if x.0.get_variable_access(false).is_some() => { - let (lhs_expr, rhs_expr, op_info) = x.as_ref(); + let (lhs_expr, op_info, rhs_expr) = x.as_ref(); let rhs_val = self .eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)? .flatten(); @@ -1998,7 +1998,7 @@ impl Engine { // lhs op= rhs Stmt::Assignment(x, op_pos) => { - let (lhs_expr, rhs_expr, op_info) = x.as_ref(); + let (lhs_expr, op_info, rhs_expr) = x.as_ref(); let rhs_val = self .eval_expr(scope, mods, state, lib, this_ptr, rhs_expr, level)? .flatten(); @@ -2083,7 +2083,9 @@ impl Engine { value.hash(hasher); let hash = hasher.finish(); - table.get(&hash).map(|StmtBlock { statements, .. }| { + table.get(&hash).map(|t| { + let statements = &t.statements; + if !statements.is_empty() { self.eval_stmt_block( scope, mods, state, lib, this_ptr, statements, true, level, @@ -2178,7 +2180,7 @@ impl Engine { // For loop Stmt::For(expr, x, _) => { - let (name, StmtBlock { statements, pos }) = x.as_ref(); + let (Ident { name, .. }, StmtBlock { statements, pos }) = x.as_ref(); let iter_obj = self .eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten(); @@ -2479,8 +2481,8 @@ impl Engine { // Share statement #[cfg(not(feature = "no_closure"))] - Stmt::Share(x) => { - if let Some((index, _)) = scope.get_index(&x.name) { + Stmt::Share(name) => { + if let Some((index, _)) = scope.get_index(name) { let val = scope.get_mut_by_index(index); if !val.is_shared() { diff --git a/src/optimize.rs b/src/optimize.rs index e4b62c26..ae0f5dce 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -385,10 +385,10 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) { match stmt { // expr op= expr Stmt::Assignment(x, _) => match x.0 { - Expr::Variable(_) => optimize_expr(&mut x.1, state), + Expr::Variable(_) => optimize_expr(&mut x.2, state), _ => { optimize_expr(&mut x.0, state); - optimize_expr(&mut x.1, state); + optimize_expr(&mut x.2, state); } }, diff --git a/src/parser.rs b/src/parser.rs index 4460539d..0925cc38 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -813,7 +813,7 @@ fn parse_switch( } } - let mut table = BTreeMap::::new(); + let mut table = BTreeMap::>::new(); let mut def_stmt = None; loop { @@ -873,7 +873,7 @@ fn parse_switch( let need_comma = !stmt.is_self_terminated(); def_stmt = if let Some(hash) = hash { - table.insert(hash, stmt.into()); + table.insert(hash, Box::new(stmt.into())); None } else { Some(stmt.into()) @@ -1390,14 +1390,14 @@ fn make_assignment_stmt<'a>( } // var (non-indexed) = rhs Expr::Variable(x) if x.0.is_none() => { - Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) + Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos)) } // var (indexed) = rhs Expr::Variable(x) => { let (index, _, Ident { name, pos, .. }) = x.as_ref(); match state.stack[(state.stack.len() - index.unwrap().get())].1 { AccessMode::ReadWrite => { - Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) + Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos)) } // Constant values cannot be assigned to AccessMode::ReadOnly => { @@ -1411,14 +1411,14 @@ fn make_assignment_stmt<'a>( Position::NONE => match &x.lhs { // var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs Expr::Variable(x) if x.0.is_none() => { - Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) + Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos)) } // var[???] (indexed) = rhs, var.??? (indexed) = rhs Expr::Variable(x) => { let (index, _, Ident { name, pos, .. }) = x.as_ref(); match state.stack[(state.stack.len() - index.unwrap().get())].1 { AccessMode::ReadWrite => { - Ok(Stmt::Assignment(Box::new((lhs, rhs, op_info)), op_pos)) + Ok(Stmt::Assignment(Box::new((lhs, op_info, rhs)), op_pos)) } // Constant values cannot be assigned to AccessMode::ReadOnly => { @@ -2091,9 +2091,9 @@ fn parse_for( settings.pos = eat_token(input, Token::For); // for name ... - let name = match input.next().unwrap() { + let (name, name_pos) = match input.next().unwrap() { // Variable name - (Token::Identifier(s), _) => s, + (Token::Identifier(s), pos) => (s, pos), // Reserved keyword (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { return Err(PERR::Reserved(s).into_err(pos)); @@ -2131,7 +2131,13 @@ fn parse_for( Ok(Stmt::For( expr, - Box::new((loop_var, body.into())), + Box::new(( + Ident { + name: loop_var, + pos: name_pos, + }, + body.into(), + )), settings.pos, )) } @@ -2766,7 +2772,7 @@ fn parse_fn( fn make_curry_from_externals( state: &mut ParseState, fn_expr: Expr, - externals: StaticVec, + externals: StaticVec, pos: Position, ) -> Expr { // If there are no captured variables, no need to curry @@ -2780,7 +2786,11 @@ fn make_curry_from_externals( args.push(fn_expr); externals.iter().for_each(|x| { - args.push(Expr::Variable(Box::new((None, None, x.clone())))); + let var_def = Ident { + name: x.clone(), + pos: Position::NONE, + }; + args.push(Expr::Variable(Box::new((None, None, var_def)))); }); let expr = Expr::FnCall( @@ -2800,7 +2810,7 @@ fn make_curry_from_externals( // Convert the entire expression into a statement block, then insert the relevant // [`Share`][Stmt::Share] statements. let mut statements: StaticVec<_> = Default::default(); - statements.extend(externals.into_iter().map(|v| Stmt::Share(Box::new(v)))); + statements.extend(externals.into_iter().map(Stmt::Share)); statements.push(Stmt::Expr(expr)); Expr::Stmt(Box::new(StmtBlock { statements, pos })) } @@ -2863,16 +2873,13 @@ fn parse_anon_fn( // External variables may need to be processed in a consistent order, // so extract them into a list. - let externals: StaticVec = { + let externals: StaticVec = { #[cfg(not(feature = "no_closure"))] { state .external_vars .iter() - .map(|(name, &pos)| Ident { - name: name.clone(), - pos, - }) + .map(|(name, _)| name.clone()) .collect() } #[cfg(feature = "no_closure")] @@ -2882,7 +2889,7 @@ fn parse_anon_fn( let params: StaticVec<_> = if cfg!(not(feature = "no_closure")) { externals .iter() - .map(|k| k.name.clone()) + .cloned() .chain(params.into_iter().map(|(v, _)| v)) .collect() } else { From 98afb2e7d64754e346b6b181c233cdb51a6abad3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 31 Mar 2021 10:16:38 +0800 Subject: [PATCH 08/10] Fix feature builds. --- .github/workflows/build.yml | 1 + CHANGELOG.md | 5 +++++ src/engine.rs | 30 ++++++++++++++------------- src/fn_native.rs | 8 +++++--- src/packages/string_basic.rs | 13 +++++++++--- src/serde/de.rs | 40 ++++++++++++++++++------------------ src/serde/deserialize.rs | 8 +++++++- src/serde/serialize.rs | 5 ++++- 8 files changed, 68 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfca586f..69823646 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,6 +35,7 @@ jobs: - "--features no_closure" - "--features unicode-xid-ident" - "--features sync,no_function,no_float,no_optimize,no_module,no_closure,metadata,serde,unchecked" + - "--features no_function,no_float,no_index,no_object,no_optimize,no_module,no_closure,unchecked" toolchain: [stable] experimental: [false] include: diff --git a/CHANGELOG.md b/CHANGELOG.md index d0421301..486e4c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,11 @@ This avoids spending precious resources maintaining metadata for functions for t use cases where such information is not required. +Bug fixes +--------- + +* The feature flags `no_index + no_object` now compile without errors. + Breaking changes ---------------- diff --git a/src/engine.rs b/src/engine.rs index 05c64223..362fb0b4 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,6 +1,6 @@ //! Main module defining the script evaluation [`Engine`]. -use crate::ast::{Expr, FnCallExpr, FnCallHash, Ident, OpAssignment, ReturnType, Stmt, StmtBlock}; +use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt, StmtBlock}; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::fn_native::{ CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback, @@ -25,8 +25,8 @@ use crate::stdlib::{ use crate::syntax::CustomSyntax; use crate::utils::get_hasher; use crate::{ - Dynamic, EvalAltResult, FnPtr, Identifier, ImmutableString, Module, Position, RhaiResult, - Scope, Shared, StaticVec, + Dynamic, EvalAltResult, FnPtr, Identifier, Module, Position, RhaiResult, Scope, Shared, + StaticVec, }; #[cfg(not(feature = "no_index"))] @@ -35,6 +35,9 @@ use crate::{calc_fn_hash, stdlib::iter::empty, Array}; #[cfg(not(feature = "no_object"))] use crate::Map; +#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] +use crate::ast::FnCallHash; + pub type Precedence = NonZeroU8; /// _(INTERNALS)_ A stack of imported [modules][Module]. @@ -394,7 +397,6 @@ impl<'a> Target<'a> { } } /// Update the value of the `Target`. - #[cfg(any(not(feature = "no_object"), not(feature = "no_index")))] pub fn set_value( &mut self, new_val: Dynamic, @@ -408,7 +410,7 @@ impl<'a> Target<'a> { Self::Value(_) => panic!("cannot update a value"), #[cfg(not(feature = "no_index"))] Self::StringChar(s, index, _) => { - let s = &mut *s.write_lock::().unwrap(); + let s = &mut *s.write_lock::().unwrap(); // Replace the character at the specified index position let new_ch = new_val.as_char().map_err(|err| { @@ -589,7 +591,7 @@ pub struct Limits { /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] pub max_modules: usize, - /// Maximum length of a [string][ImmutableString]. + /// Maximum length of a [string][crate::ImmutableString]. pub max_string_size: Option, /// Maximum length of an [array][Array]. /// @@ -1569,8 +1571,8 @@ impl Engine { #[cfg(not(feature = "no_object"))] Dynamic(Union::Map(map, _)) => { // val_map[idx] - let index = &*idx.read_lock::().ok_or_else(|| { - self.make_type_mismatch_err::(idx.type_name(), idx_pos) + let index = &*idx.read_lock::().ok_or_else(|| { + self.make_type_mismatch_err::(idx.type_name(), idx_pos) })?; if _create && !map.contains_key(index.as_str()) { @@ -2427,7 +2429,7 @@ impl Engine { if let Some(path) = self .eval_expr(scope, mods, state, lib, this_ptr, &expr, level)? - .try_cast::() + .try_cast::() { use crate::ModuleResolver; @@ -2460,7 +2462,7 @@ impl Engine { Ok(Dynamic::UNIT) } else { - Err(self.make_type_mismatch_err::("", expr.position())) + Err(self.make_type_mismatch_err::("", expr.position())) } } @@ -2515,17 +2517,17 @@ impl Engine { } // If no data size limits, just return - let mut has_limit = self.limits.max_string_size.is_some(); + let mut _has_limit = self.limits.max_string_size.is_some(); #[cfg(not(feature = "no_index"))] { - has_limit = has_limit || self.limits.max_array_size.is_some(); + _has_limit = _has_limit || self.limits.max_array_size.is_some(); } #[cfg(not(feature = "no_object"))] { - has_limit = has_limit || self.limits.max_map_size.is_some(); + _has_limit = _has_limit || self.limits.max_map_size.is_some(); } - if !has_limit { + if !_has_limit { return result; } diff --git a/src/fn_native.rs b/src/fn_native.rs index 4535cf8f..f14ce5e6 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -13,8 +13,8 @@ use crate::stdlib::{ }; use crate::token::is_valid_identifier; use crate::{ - calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, Identifier, ImmutableString, Module, - Position, RhaiResult, StaticVec, + calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ImmutableString, Module, Position, + RhaiResult, StaticVec, }; /// Trait that maps to `Send + Sync` only under the `sync` feature. @@ -144,7 +144,9 @@ impl<'a> NativeCallContext<'a> { #[cfg(not(feature = "no_module"))] #[allow(dead_code)] #[inline(always)] - pub(crate) fn iter_imports_raw(&self) -> impl Iterator)> { + pub(crate) fn iter_imports_raw( + &self, + ) -> impl Iterator)> { self.mods.iter().flat_map(|&m| m.iter_raw()) } /// _(INTERNALS)_ The current set of modules imported via `import` statements. diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 08839b5b..69f1e392 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -2,7 +2,7 @@ use crate::plugin::*; use crate::stdlib::{format, string::ToString}; -use crate::{def_package, FnPtr, ImmutableString}; +use crate::{def_package, FnPtr}; #[cfg(not(feature = "no_index"))] use crate::Array; @@ -10,6 +10,7 @@ use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; +#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] const FUNC_TO_DEBUG: &'static str = "to_debug"; def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, { @@ -20,9 +21,15 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[inline(always)] -fn print_with_func(fn_name: &str, ctx: &NativeCallContext, value: &mut Dynamic) -> ImmutableString { +fn print_with_func( + fn_name: &str, + ctx: &NativeCallContext, + value: &mut Dynamic, +) -> crate::ImmutableString { match ctx.call_fn_dynamic_raw(fn_name, true, &mut [value]) { - Ok(result) if result.is::() => result.take_immutable_string().unwrap(), + Ok(result) if result.is::() => { + result.take_immutable_string().unwrap() + } Ok(result) => ctx.engine().map_type_name(result.type_name()).into(), Err(_) => ctx.engine().map_type_name(value.type_name()).into(), } diff --git a/src/serde/de.rs b/src/serde/de.rs index faf98d71..802a47e2 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -183,7 +183,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x)) } } @@ -193,7 +193,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x)) } } @@ -205,7 +205,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x)) } } @@ -217,7 +217,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x)) } } @@ -229,7 +229,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.type_error() } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x)) } } @@ -239,7 +239,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x)) } } @@ -249,7 +249,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x)) } } @@ -259,7 +259,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x)) } } @@ -269,7 +269,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x)) } } @@ -279,7 +279,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self.deserialize_int(v, visitor) } else { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x)) } } @@ -288,7 +288,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_float"))] return self .value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x)); #[cfg(feature = "no_float")] @@ -298,7 +298,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { return self .value - .downclone_cast::() + .downcast_ref::() .and_then(|&x| x.to_f32()) .map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v)); } @@ -312,7 +312,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { #[cfg(not(feature = "no_float"))] return self .value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x)); #[cfg(feature = "no_float")] @@ -322,7 +322,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { return self .value - .downclone_cast::() + .downcast_ref::() .and_then(|&x| x.to_f64()) .map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v)); } @@ -334,12 +334,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_char>(self, visitor: V) -> Result> { self.value - .downclone_cast::() + .downcast_ref::() .map_or_else(|| self.type_error(), |&x| visitor.visit_char(x)) } fn deserialize_str>(self, visitor: V) -> Result> { - self.value.downclone_cast::().map_or_else( + self.value.downcast_ref::().map_or_else( || self.type_error(), |x| visitor.visit_borrowed_str(x.as_str()), ) @@ -366,7 +366,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_unit>(self, visitor: V) -> Result> { self.value - .downclone_cast::<()>() + .downcast_ref::<()>() .map_or_else(|| self.type_error(), |_| visitor.visit_unit()) } @@ -388,7 +388,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_seq>(self, _visitor: V) -> Result> { #[cfg(not(feature = "no_index"))] - return self.value.downclone_cast::().map_or_else( + return self.value.downcast_ref::().map_or_else( || self.type_error(), |arr| _visitor.visit_seq(IterateArray::new(arr.iter())), ); @@ -416,7 +416,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { fn deserialize_map>(self, _visitor: V) -> Result> { #[cfg(not(feature = "no_object"))] - return self.value.downclone_cast::().map_or_else( + return self.value.downcast_ref::().map_or_else( || self.type_error(), |map| { _visitor.visit_map(IterateMap::new( @@ -449,7 +449,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { visitor.visit_enum(s.as_str().into_deserializer()) } else { #[cfg(not(feature = "no_object"))] - if let Some(map) = self.value.downclone_cast::() { + if let Some(map) = self.value.downcast_ref::() { let mut iter = map.iter(); let first = iter.next(); let second = iter.next(); diff --git a/src/serde/deserialize.rs b/src/serde/deserialize.rs index cd8c852a..a507eb0c 100644 --- a/src/serde/deserialize.rs +++ b/src/serde/deserialize.rs @@ -2,14 +2,20 @@ use crate::stdlib::{fmt, string::ToString}; use crate::{Dynamic, ImmutableString, INT}; -use serde::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor}; +use serde::de::{Deserialize, Deserializer, Error, Visitor}; #[cfg(not(feature = "no_index"))] use crate::Array; +#[cfg(not(feature = "no_index"))] +use serde::de::SeqAccess; + #[cfg(not(feature = "no_object"))] use crate::Map; +#[cfg(not(feature = "no_object"))] +use serde::de::MapAccess; + struct DynamicVisitor; impl<'d> Visitor<'d> for DynamicVisitor { diff --git a/src/serde/serialize.rs b/src/serde/serialize.rs index 2491b2f9..e5f3f6a4 100644 --- a/src/serde/serialize.rs +++ b/src/serde/serialize.rs @@ -3,7 +3,10 @@ use crate::dynamic::{Union, Variant}; use crate::stdlib::string::ToString; use crate::{Dynamic, ImmutableString}; -use serde::ser::{Serialize, SerializeMap, Serializer}; +use serde::ser::{Serialize, Serializer}; + +#[cfg(not(feature = "no_object"))] +use serde::ser::SerializeMap; impl Serialize for Dynamic { fn serialize(&self, ser: S) -> Result { From 961e5a6cd8548de29b6077761e3ff2fe76eb7a17 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 31 Mar 2021 10:27:53 +0800 Subject: [PATCH 09/10] Add metadata flag to codegen tests. --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69823646..8d5dedd2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,6 +111,8 @@ jobs: continue-on-error: ${{matrix.experimental}} strategy: matrix: + flags: + - "--features metadata" include: - {toolchain: nightly, os: ubuntu-latest, experimental: false, flags: ""} - {toolchain: nightly, os: windows-latest, experimental: false, flags: ""} From 35394e170a9003d32a302d5aff2d1875f67f2c4d Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 31 Mar 2021 10:30:52 +0800 Subject: [PATCH 10/10] Move flags into include. --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d5dedd2..26553d24 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,11 +111,9 @@ jobs: continue-on-error: ${{matrix.experimental}} strategy: matrix: - flags: - - "--features metadata" include: - - {toolchain: nightly, os: ubuntu-latest, experimental: false, flags: ""} - - {toolchain: nightly, os: windows-latest, experimental: false, flags: ""} + - {toolchain: nightly, os: ubuntu-latest, experimental: false, flags: "--features metadata"} + - {toolchain: nightly, os: windows-latest, experimental: false, flags: "--features metadata"} steps: - name: Checkout uses: actions/checkout@v2