diff --git a/minijinja/Cargo.toml b/minijinja/Cargo.toml index bfe7b39b..5db4f58b 100644 --- a/minijinja/Cargo.toml +++ b/minijinja/Cargo.toml @@ -16,18 +16,19 @@ features = ["source", "json", "urlencode"] rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "doc-header.html"] [features] -default = ["builtins", "sync", "debug", "key_interning", "deserialization"] -sync = [] +default = ["builtins", "debug", "key_interning", "deserialization"] deserialization = [] -key_interning = ["sync"] +key_interning = [] preserve_order = ["indexmap"] -debug = ["sync"] +debug = [] speedups = ["v_htmlescape"] source = ["self_cell", "memo-map"] builtins = [] json = ["serde_json"] urlencode = ["percent-encoding"] +# this feature no longer has any effect +sync = [] # enables the Debug trait for some internal types internal_debug = [] # provides access to the unstable machinery diff --git a/minijinja/src/environment.rs b/minijinja/src/environment.rs index 0d3419f5..31056749 100644 --- a/minijinja/src/environment.rs +++ b/minijinja/src/environment.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; use std::fmt; +use std::sync::Arc; use serde::Serialize; @@ -8,7 +9,7 @@ use crate::error::Error; use crate::instructions::Instructions; use crate::parser::{parse, parse_expr}; use crate::utils::{AutoEscape, BTreeMapKeysDebug, HtmlEscape}; -use crate::value::{ArgType, FunctionArgs, RcType, Value}; +use crate::value::{ArgType, FunctionArgs, Value}; use crate::vm::Vm; use crate::{filters, functions, tests}; @@ -202,7 +203,7 @@ pub struct Environment<'source> { filters: BTreeMap<&'source str, filters::BoxedFilter>, tests: BTreeMap<&'source str, tests::BoxedTest>, pub(crate) globals: BTreeMap<&'source str, Value>, - default_auto_escape: RcType AutoEscape + Sync + Send>, + default_auto_escape: Arc AutoEscape + Sync + Send>, #[cfg(feature = "debug")] debug: bool, } @@ -309,7 +310,7 @@ impl<'source> Environment<'source> { filters: filters::get_builtin_filters(), tests: tests::get_builtin_tests(), globals: functions::get_globals(), - default_auto_escape: RcType::new(default_auto_escape), + default_auto_escape: Arc::new(default_auto_escape), #[cfg(feature = "debug")] debug: cfg!(debug_assertions), } @@ -325,7 +326,7 @@ impl<'source> Environment<'source> { filters: Default::default(), tests: Default::default(), globals: Default::default(), - default_auto_escape: RcType::new(no_auto_escape), + default_auto_escape: Arc::new(no_auto_escape), #[cfg(feature = "debug")] debug: cfg!(debug_assertions), } @@ -349,7 +350,7 @@ impl<'source> Environment<'source> { &mut self, f: F, ) { - self.default_auto_escape = RcType::new(f); + self.default_auto_escape = Arc::new(f); } /// Enable or disable the debug mode. diff --git a/minijinja/src/filters.rs b/minijinja/src/filters.rs index e45ca59a..aa1de55d 100644 --- a/minijinja/src/filters.rs +++ b/minijinja/src/filters.rs @@ -45,16 +45,17 @@ //! MiniJinja will perform the necessary conversions automatically via the //! [`FunctionArgs`](crate::value::FunctionArgs) and [`Into`] traits. use std::collections::BTreeMap; +use std::sync::Arc; use crate::error::Error; -use crate::value::{ArgType, FunctionArgs, RcType, Value}; +use crate::value::{ArgType, FunctionArgs, Value}; use crate::vm::State; use crate::AutoEscape; type FilterFunc = dyn Fn(&State, &Value, &[Value]) -> Result + Sync + Send + 'static; #[derive(Clone)] -pub(crate) struct BoxedFilter(RcType); +pub(crate) struct BoxedFilter(Arc); /// A utility trait that represents filters. pub trait Filter: Send + Sync + 'static { @@ -93,7 +94,7 @@ impl BoxedFilter { Rv: Into, Args: for<'a> FunctionArgs<'a>, { - BoxedFilter(RcType::new( + BoxedFilter(Arc::new( move |state, value, args| -> Result { f.apply_to( state, diff --git a/minijinja/src/key/mod.rs b/minijinja/src/key/mod.rs index 5fe9a544..c3941911 100644 --- a/minijinja/src/key/mod.rs +++ b/minijinja/src/key/mod.rs @@ -3,9 +3,10 @@ use std::convert::TryFrom; use std::fmt; use std::hash::{Hash, Hasher}; use std::num::TryFromIntError; +use std::sync::Arc; use crate::error::{Error, ErrorKind}; -use crate::value::{RcType, Value, ValueRepr}; +use crate::value::{Value, ValueRepr}; pub use crate::key::serialize::KeySerializer; @@ -19,7 +20,7 @@ pub enum Key<'a> { Bool(bool), I64(i64), Char(char), - String(RcType), + String(Arc), Str(&'a str), } @@ -53,7 +54,7 @@ impl<'a> Key<'a> { } #[cfg(not(feature = "key_interning"))] { - Key::String(RcType::new(String::from(s))) + Key::String(Arc::new(String::from(s))) } } @@ -197,7 +198,7 @@ pub mod key_interning { enum CachedKey<'a> { Ref(&'a str), - Stored(RcType), + Stored(Arc), } impl<'a> CachedKey<'a> { @@ -237,14 +238,14 @@ pub mod key_interning { }) } - pub(crate) fn try_intern(s: &str) -> RcType { + pub(crate) fn try_intern(s: &str) -> Arc { let depth = STRING_KEY_CACHE_DEPTH.with(|depth| depth.load(Ordering::Relaxed)); // strings longer than 16 bytes are never interned or if we're at // depth 0. (serialization code outside of internal serialization) // not checking for depth can cause a memory leak. if depth == 0 || s.len() > 16 { - return RcType::new(String::from(s)); + return Arc::new(String::from(s)); } STRING_KEY_CACHE.with(|cache| { @@ -252,7 +253,7 @@ pub mod key_interning { match set.get(&CachedKey::Ref(s)) { Some(CachedKey::Stored(s)) => s.clone(), None => { - let rv = RcType::new(String::from(s)); + let rv = Arc::new(String::from(s)); set.insert(CachedKey::Stored(rv.clone())); rv } diff --git a/minijinja/src/lib.rs b/minijinja/src/lib.rs index f4069f30..63f0a329 100644 --- a/minijinja/src/lib.rs +++ b/minijinja/src/lib.rs @@ -112,11 +112,6 @@ //! //! - `builtins`: if this feature is removed the default filters, tests and //! functions are not implemented. -//! - `sync`: this feature makes MiniJinja's type `Send` and `Sync`. If this feature -//! is disabled sending types across threads is often not possible. Thread bounds -//! of things like callbacks however are not changing which means code that uses -//! MiniJinja still needs to be threadsafe. This also disables some features that -//! require synchronization such as the `loop.changed` feature. //! - `debug`: if this feature is removed some debug functionality of the engine is //! removed as well. This mainly affects the quality of error reporting. //! - `key_interning`: if this feature is removed the automatic string interning in diff --git a/minijinja/src/macros.rs b/minijinja/src/macros.rs index 7400daa2..4b7898fd 100644 --- a/minijinja/src/macros.rs +++ b/minijinja/src/macros.rs @@ -5,8 +5,9 @@ use similar_asserts::assert_eq; #[doc(hidden)] pub mod __context { use crate::key::Key; - use crate::value::{RcType, Value, ValueMap, ValueRepr}; + use crate::value::{Value, ValueMap, ValueRepr}; use crate::Environment; + use std::sync::Arc; #[inline(always)] pub fn make() -> ValueMap { @@ -20,7 +21,7 @@ pub mod __context { #[inline(always)] pub fn build(ctx: ValueMap) -> Value { - ValueRepr::Map(RcType::new(ctx)).into() + ValueRepr::Map(Arc::new(ctx)).into() } pub fn thread_local_env() -> Environment<'static> { diff --git a/minijinja/src/source.rs b/minijinja/src/source.rs index cd1310b3..79282d2a 100644 --- a/minijinja/src/source.rs +++ b/minijinja/src/source.rs @@ -9,7 +9,6 @@ use self_cell::self_cell; use crate::environment::CompiledTemplate; use crate::error::{Error, ErrorKind}; -use crate::value::RcType; #[cfg(test)] use similar_asserts::assert_eq; @@ -39,11 +38,11 @@ pub struct Source { #[derive(Clone)] enum SourceBacking { Dynamic { - templates: MemoMap>, + templates: MemoMap>, loader: Arc, }, Static { - templates: HashMap>, + templates: HashMap>, }, } @@ -162,10 +161,10 @@ impl Source { SourceBacking::Dynamic { ref mut templates, .. } => { - templates.replace(name, RcType::new(tmpl)); + templates.replace(name, Arc::new(tmpl)); } SourceBacking::Static { ref mut templates } => { - templates.insert(name, RcType::new(tmpl)); + templates.insert(name, Arc::new(tmpl)); } } Ok(()) @@ -262,7 +261,7 @@ impl Source { LoadedTemplate::try_new(owner, |(name, source)| -> Result<_, Error> { CompiledTemplate::from_name_and_source(name.as_str(), source) })?; - Ok(RcType::new(tmpl)) + Ok(Arc::new(tmpl)) })? .borrow_dependent()), SourceBacking::Static { templates } => templates diff --git a/minijinja/src/syntax.rs b/minijinja/src/syntax.rs index 309c6b8c..3796f8a5 100644 --- a/minijinja/src/syntax.rs +++ b/minijinja/src/syntax.rs @@ -207,9 +207,9 @@ //! {% endfor %} //! ``` //! -//! If the `sync` feature is not disabled, the `loop.changed` helper is also available -//! which can be used to detect when a value changes between the last iteration and the -//! current one. The method takes one or more arguments that are all compared. +//! A `loop.changed()` helper is also available which can be used to detect when +//! a value changes between the last iteration and the current one. The method +//! takes one or more arguments that are all compared. //! //! ```jinja //! {% for entry in entries %} diff --git a/minijinja/src/tests.rs b/minijinja/src/tests.rs index 7c7ae6af..f0a135da 100644 --- a/minijinja/src/tests.rs +++ b/minijinja/src/tests.rs @@ -46,15 +46,16 @@ //! MiniJinja will perform the necessary conversions automatically via the //! [`FunctionArgs`](crate::value::FunctionArgs) trait. use std::collections::BTreeMap; +use std::sync::Arc; use crate::error::Error; -use crate::value::{ArgType, FunctionArgs, RcType, Value}; +use crate::value::{ArgType, FunctionArgs, Value}; use crate::vm::State; type TestFunc = dyn Fn(&State, &Value, &[Value]) -> Result + Sync + Send + 'static; #[derive(Clone)] -pub(crate) struct BoxedTest(RcType); +pub(crate) struct BoxedTest(Arc); /// A utility trait that represents filters. pub trait Test: Send + Sync + 'static { @@ -92,16 +93,14 @@ impl BoxedTest { V: for<'a> ArgType<'a>, Args: for<'a> FunctionArgs<'a>, { - BoxedTest(RcType::new( - move |state, value, args| -> Result { - let value = Some(value); - f.perform( - state, - ArgType::from_value(value)?, - FunctionArgs::from_values(args)?, - ) - }, - )) + BoxedTest(Arc::new(move |state, value, args| -> Result { + let value = Some(value); + f.perform( + state, + ArgType::from_value(value)?, + FunctionArgs::from_values(args)?, + ) + })) } /// Applies the filter to a value and argument. diff --git a/minijinja/src/value/argtypes.rs b/minijinja/src/value/argtypes.rs index 301f9dd8..72881865 100644 --- a/minijinja/src/value/argtypes.rs +++ b/minijinja/src/value/argtypes.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use crate::error::{Error, ErrorKind}; use crate::key::{Key, StaticKey}; -use crate::value::{RcType, Value, ValueRepr}; +use crate::value::{Arc, Value, ValueRepr}; /// Helper trait representing valid filter and test arguments. /// @@ -76,21 +76,21 @@ impl From for Value { impl<'a> From<&'a [u8]> for Value { #[inline(always)] fn from(val: &'a [u8]) -> Self { - ValueRepr::Bytes(RcType::new(val.into())).into() + ValueRepr::Bytes(Arc::new(val.into())).into() } } impl<'a> From<&'a str> for Value { #[inline(always)] fn from(val: &'a str) -> Self { - ValueRepr::String(RcType::new(val.into())).into() + ValueRepr::String(Arc::new(val.into())).into() } } impl From for Value { #[inline(always)] fn from(val: String) -> Self { - ValueRepr::String(RcType::new(val)).into() + ValueRepr::String(Arc::new(val)).into() } } @@ -114,14 +114,14 @@ impl From<()> for Value { impl From for Value { #[inline(always)] fn from(val: i128) -> Self { - ValueRepr::I128(RcType::new(val)).into() + ValueRepr::I128(Arc::new(val)).into() } } impl From for Value { #[inline(always)] fn from(val: u128) -> Self { - ValueRepr::U128(RcType::new(val)).into() + ValueRepr::U128(Arc::new(val)).into() } } @@ -139,7 +139,7 @@ impl<'a> From> for Value { impl, V: Into> From> for Value { fn from(val: BTreeMap) -> Self { - ValueRepr::Map(RcType::new( + ValueRepr::Map(Arc::new( val.into_iter().map(|(k, v)| (k.into(), v.into())).collect(), )) .into() @@ -148,7 +148,7 @@ impl, V: Into> From> for Value { impl> From> for Value { fn from(val: Vec) -> Self { - ValueRepr::Seq(RcType::new(val.into_iter().map(|x| x.into()).collect())).into() + ValueRepr::Seq(Arc::new(val.into_iter().map(|x| x.into()).collect())).into() } } diff --git a/minijinja/src/value/mod.rs b/minijinja/src/value/mod.rs index 2424e212..887060ae 100644 --- a/minijinja/src/value/mod.rs +++ b/minijinja/src/value/mod.rs @@ -73,6 +73,7 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt; use std::sync::atomic::{self, AtomicBool, AtomicUsize}; +use std::sync::Arc; use serde::ser::{Serialize, Serializer}; @@ -95,12 +96,6 @@ mod serialize; #[cfg(test)] use similar_asserts::assert_eq; -#[cfg(feature = "sync")] -pub(crate) type RcType = std::sync::Arc; - -#[cfg(not(feature = "sync"))] -pub(crate) type RcType = std::rc::Rc; - // We use in-band signalling to roundtrip some internal values. This is // not ideal but unfortunately there is no better system in serde today. const VALUE_HANDLE_MARKER: &str = "\x01__minijinja_ValueHandle"; @@ -207,14 +202,14 @@ pub(crate) enum ValueRepr { F64(f64), Char(char), None, - U128(RcType), - I128(RcType), - String(RcType), - SafeString(RcType), - Bytes(RcType>), - Seq(RcType>), - Map(RcType), - Dynamic(RcType), + U128(Arc), + I128(Arc), + String(Arc), + SafeString(Arc), + Bytes(Arc>), + Seq(Arc>), + Map(Arc), + Dynamic(Arc), } impl fmt::Debug for ValueRepr { @@ -353,17 +348,17 @@ impl Value { /// Creates a value from a safe string. pub fn from_safe_string(value: String) -> Value { - ValueRepr::SafeString(RcType::new(value)).into() + ValueRepr::SafeString(Arc::new(value)).into() } /// Creates a value from a reference counted dynamic object. - pub(crate) fn from_rc_object(value: RcType) -> Value { - ValueRepr::Dynamic(value as RcType).into() + pub(crate) fn from_rc_object(value: Arc) -> Value { + ValueRepr::Dynamic(value as Arc).into() } /// Creates a value from a dynamic object. pub fn from_object(value: T) -> Value { - Value::from_rc_object(RcType::new(value)) + Value::from_rc_object(Arc::new(value)) } /// Returns some reference to the boxed object if it is of type `T`, or None if it isn’t. @@ -399,12 +394,12 @@ impl Value { unsafe { // newer versions of Rust have RcType::as_ptr but we support // rust versions down to 1.41.0 so we need to use a workaround here. - let count = RcType::strong_count(obj); + let count = Arc::strong_count(obj); let clone = obj.clone(); - let raw: *const (dyn Object) = RcType::into_raw(clone); + let raw: *const (dyn Object) = Arc::into_raw(clone); let rv = (raw as *const u8 as *const T).as_ref(); - RcType::from_raw(raw); - debug_assert_eq!(count, RcType::strong_count(obj)); + Arc::from_raw(raw); + debug_assert_eq!(count, Arc::strong_count(obj)); return rv; } } @@ -624,17 +619,16 @@ impl Value { /// Iterates over the value. pub(crate) fn iter(&self) -> ValueIterator { let (iter_state, len) = match self.0 { - ValueRepr::Seq(ref seq) => (ValueIteratorState::Seq(0, RcType::clone(seq)), seq.len()), + ValueRepr::Seq(ref seq) => (ValueIteratorState::Seq(0, Arc::clone(seq)), seq.len()), #[cfg(feature = "preserve_order")] - ValueRepr::Map(ref items) => ( - ValueIteratorState::Map(0, RcType::clone(items)), - items.len(), - ), + ValueRepr::Map(ref items) => { + (ValueIteratorState::Map(0, Arc::clone(items)), items.len()) + } #[cfg(not(feature = "preserve_order"))] ValueRepr::Map(ref items) => ( ValueIteratorState::Map( items.iter().next().map(|x| x.0.clone()), - RcType::clone(items), + Arc::clone(items), ), items.len(), ), @@ -725,11 +719,11 @@ impl fmt::Debug for ValueIterator { enum ValueIteratorState { Empty, - Seq(usize, RcType>), + Seq(usize, Arc>), #[cfg(not(feature = "preserve_order"))] - Map(Option, RcType), + Map(Option, Arc), #[cfg(feature = "preserve_order")] - Map(usize, RcType), + Map(usize, Arc), } impl ValueIteratorState { @@ -898,7 +892,7 @@ fn test_dynamic_object_roundtrip() { } } - let x = RcType::new(X(Default::default())); + let x = Arc::new(X(Default::default())); let x_value = Value::from_rc_object(x.clone()); x.0.fetch_add(42, atomic::Ordering::Relaxed); let x_clone = Value::from_serializable(&x_value); @@ -911,7 +905,7 @@ fn test_dynamic_object_roundtrip() { #[test] fn test_string_key_lookup() { let mut m = BTreeMap::new(); - m.insert(Key::String(RcType::new("foo".into())), Value::from(42)); + m.insert(Key::String(Arc::new("foo".into())), Value::from(42)); let m = Value::from(m); assert_eq!(m.get_item(&Value::from("foo")).unwrap(), Value::from(42)); } @@ -960,7 +954,7 @@ fn test_key_interning() { let k = m.iter().next().unwrap().0; match k { Key::String(s) => { - assert_eq!(RcType::strong_count(s), 3); + assert_eq!(Arc::strong_count(s), 3); } _ => unreachable!(), } diff --git a/minijinja/src/value/ops.rs b/minijinja/src/value/ops.rs index 8f741850..6fbde97c 100644 --- a/minijinja/src/value/ops.rs +++ b/minijinja/src/value/ops.rs @@ -2,7 +2,7 @@ use std::convert::TryFrom; use std::fmt::Write; use crate::error::{Error, ErrorKind}; -use crate::value::{RcType, Value, ValueKind, ValueRepr}; +use crate::value::{Arc, Value, ValueKind, ValueRepr}; pub enum CoerceResult { I128(i128, i128), @@ -159,7 +159,7 @@ pub fn string_concat(mut left: Value, right: &Value) -> Value { // if we're a string and we have a single reference to it, we can // directly append into ourselves and reconstruct the value ValueRepr::String(ref mut s) => { - write!(RcType::make_mut(s), "{}", right).ok(); + write!(Arc::make_mut(s), "{}", right).ok(); left } // otherwise we use format! to concat the two values diff --git a/minijinja/src/value/serialize.rs b/minijinja/src/value/serialize.rs index d137f2c4..544ffb1c 100644 --- a/minijinja/src/value/serialize.rs +++ b/minijinja/src/value/serialize.rs @@ -4,7 +4,7 @@ use serde::{ser, Serialize, Serializer}; use crate::error::Error; use crate::key::{Key, KeySerializer, StaticKey}; -use crate::value::{RcType, Value, ValueMap, ValueRepr, VALUE_HANDLES, VALUE_HANDLE_MARKER}; +use crate::value::{Arc, Value, ValueMap, ValueRepr, VALUE_HANDLES, VALUE_HANDLE_MARKER}; pub struct ValueSerializer; @@ -41,7 +41,7 @@ impl Serializer for ValueSerializer { } fn serialize_i128(self, v: i128) -> Result { - Ok(ValueRepr::I128(RcType::new(v)).into()) + Ok(ValueRepr::I128(Arc::new(v)).into()) } fn serialize_u8(self, v: u8) -> Result { @@ -61,7 +61,7 @@ impl Serializer for ValueSerializer { } fn serialize_u128(self, v: u128) -> Result { - Ok(ValueRepr::U128(RcType::new(v)).into()) + Ok(ValueRepr::U128(Arc::new(v)).into()) } fn serialize_f32(self, v: f32) -> Result { @@ -77,11 +77,11 @@ impl Serializer for ValueSerializer { } fn serialize_str(self, value: &str) -> Result { - Ok(ValueRepr::String(RcType::new(value.to_owned())).into()) + Ok(ValueRepr::String(Arc::new(value.to_owned())).into()) } fn serialize_bytes(self, value: &[u8]) -> Result { - Ok(ValueRepr::Bytes(RcType::new(value.to_owned())).into()) + Ok(ValueRepr::Bytes(Arc::new(value.to_owned())).into()) } fn serialize_none(self) -> Result { @@ -109,7 +109,7 @@ impl Serializer for ValueSerializer { _variant_index: u32, variant: &'static str, ) -> Result { - Ok(ValueRepr::String(RcType::new(variant.to_string())).into()) + Ok(ValueRepr::String(Arc::new(variant.to_string())).into()) } fn serialize_newtype_struct( @@ -135,7 +135,7 @@ impl Serializer for ValueSerializer { { let mut map = ValueMap::new(); map.insert(Key::from(variant), value.serialize(self)?); - Ok(ValueRepr::Map(RcType::new(map)).into()) + Ok(ValueRepr::Map(Arc::new(map)).into()) } fn serialize_seq(self, len: Option) -> Result { @@ -223,7 +223,7 @@ impl ser::SerializeSeq for SerializeSeq { } fn end(self) -> Result { - Ok(ValueRepr::Seq(RcType::new(self.elements)).into()) + Ok(ValueRepr::Seq(Arc::new(self.elements)).into()) } } @@ -245,7 +245,7 @@ impl ser::SerializeTuple for SerializeTuple { } fn end(self) -> Result { - Ok(ValueRepr::Seq(RcType::new(self.elements)).into()) + Ok(ValueRepr::Seq(Arc::new(self.elements)).into()) } } @@ -267,7 +267,7 @@ impl ser::SerializeTupleStruct for SerializeTupleStruct { } fn end(self) -> Result { - Ok(Value(ValueRepr::Seq(RcType::new(self.fields)))) + Ok(Value(ValueRepr::Seq(Arc::new(self.fields)))) } } @@ -328,7 +328,7 @@ impl ser::SerializeMap for SerializeMap { } fn end(self) -> Result { - Ok(Value(ValueRepr::Map(RcType::new(self.entries)))) + Ok(Value(ValueRepr::Map(Arc::new(self.entries)))) } fn serialize_entry(&mut self, key: &K, value: &V) -> Result<(), Error> @@ -375,7 +375,7 @@ impl ser::SerializeStruct for SerializeStruct { .expect("value handle not in registry") })) } - _ => Ok(ValueRepr::Map(RcType::new(self.fields)).into()), + _ => Ok(ValueRepr::Map(Arc::new(self.fields)).into()), } } } @@ -402,7 +402,7 @@ impl ser::SerializeStructVariant for SerializeStructVariant { let mut rv = BTreeMap::new(); rv.insert( self.variant, - Value::from(ValueRepr::Map(RcType::new(self.map))), + Value::from(ValueRepr::Map(Arc::new(self.map))), ); Ok(rv.into()) } diff --git a/minijinja/src/vm.rs b/minijinja/src/vm.rs index 527be33c..2e9ac49a 100644 --- a/minijinja/src/vm.rs +++ b/minijinja/src/vm.rs @@ -1,8 +1,7 @@ use std::collections::{BTreeMap, HashSet}; use std::fmt::{self, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; -#[cfg(feature = "sync")] -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use crate::environment::Environment; use crate::error::{Error, ErrorKind}; @@ -10,14 +9,13 @@ use crate::instructions::{ Instruction, Instructions, LOOP_FLAG_RECURSIVE, LOOP_FLAG_WITH_LOOP_VAR, }; use crate::key::Key; -use crate::value::{self, ops, Object, RcType, Value, ValueIterator, ValueRepr}; +use crate::value::{self, ops, Object, Value, ValueIterator, ValueRepr}; use crate::AutoEscape; pub struct LoopState { len: usize, idx: AtomicUsize, depth: usize, - #[cfg(feature = "sync")] last_changed_value: Mutex>>, } @@ -71,21 +69,17 @@ impl Object for LoopState { } fn call_method(&self, _state: &State, name: &str, args: &[Value]) -> Result { - #[cfg(feature = "sync")] - { - if name == "changed" { - let mut last_changed_value = self.last_changed_value.lock().unwrap(); - let value = args.to_owned(); - let changed = last_changed_value.as_ref() != Some(&value); - if changed { - *last_changed_value = Some(value); - return Ok(Value::from(true)); - } - return Ok(Value::from(false)); + if name == "changed" { + let mut last_changed_value = self.last_changed_value.lock().unwrap(); + let value = args.to_owned(); + let changed = last_changed_value.as_ref() != Some(&value); + if changed { + *last_changed_value = Some(value); + Ok(Value::from(true)) + } else { + Ok(Value::from(false)) } - } - - if name == "cycle" { + } else if name == "cycle" { let idx = self.idx.load(Ordering::Relaxed); match args.get(idx % args.len()) { Some(arg) => Ok(arg.clone()), @@ -122,7 +116,7 @@ pub struct Loop { // tells us if we need to end capturing. current_recursion_jump: Option<(usize, bool)>, iterator: ValueIterator, - controller: RcType, + controller: Arc, } #[cfg_attr(feature = "internal_debug", derive(Debug))] @@ -688,7 +682,7 @@ impl<'env> Vm<'env> { v.push(stack.pop()); } v.reverse(); - stack.push(Value(ValueRepr::Seq(RcType::new(v)))); + stack.push(Value(ValueRepr::Seq(Arc::new(v)))); } Instruction::UnpackList(count) => { let top = stack.pop(); @@ -716,7 +710,7 @@ impl<'env> Vm<'env> { Instruction::ListAppend => { let item = stack.pop(); if let ValueRepr::Seq(mut v) = stack.pop().0 { - RcType::make_mut(&mut v).push(item); + Arc::make_mut(&mut v).push(item); stack.push(Value(ValueRepr::Seq(v))) } else { bail!(Error::new( @@ -787,11 +781,10 @@ impl<'env> Vm<'env> { with_loop_var: *flags & LOOP_FLAG_WITH_LOOP_VAR != 0, recurse_jump_target: if recursive { Some(pc) } else { None }, current_recursion_jump: next_loop_recursion_jump.take(), - controller: RcType::new(LoopState { + controller: Arc::new(LoopState { idx: AtomicUsize::new(!0usize), len, depth, - #[cfg(feature = "sync")] last_changed_value: Mutex::default(), }), }), diff --git a/minijinja/tests/test_templates.rs b/minijinja/tests/test_templates.rs index 449c355d..64167439 100644 --- a/minijinja/tests/test_templates.rs +++ b/minijinja/tests/test_templates.rs @@ -118,7 +118,6 @@ fn test_auto_escaping() { insta::assert_snapshot!(rv, @r###"foo"bar'baz"###); } -#[cfg(feature = "sync")] #[test] fn test_loop_changed() { let rv = minijinja::render!(