git.delta.rocks / jrsonnet / refs/commits / 068a27ea4069

difftreelog

feat make std.map accept strings

Yaroslav Bolyukin2023-05-03parent: #bd9176f.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
1use std::rc::Rc;
2
1use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};
2use jrsonnet_interner::IBytes;4use jrsonnet_interner::IBytes;
14pub enum ArrValue {16pub enum ArrValue {
15 /// Layout optimized byte array.17 /// Layout optimized byte array.
16 Bytes(BytesArray),18 Bytes(BytesArray),
19 /// Layout optimized char array.
20 Chars(CharArray),
17 /// Every element is lazy evaluated.21 /// Every element is lazy evaluated.
18 Lazy(LazyArray),22 Lazy(LazyArray),
19 /// Every element is defined somewhere in source code23 /// Every element is defined somewhere in source code
66 pub fn bytes(bytes: IBytes) -> Self {70 pub fn bytes(bytes: IBytes) -> Self {
67 Self::Bytes(BytesArray(bytes))71 Self::Bytes(BytesArray(bytes))
68 }72 }
73 pub fn chars(chars: impl Iterator<Item = char>) -> Self {
74 Self::Chars(CharArray(Rc::new(chars.collect())))
75 }
6976
70 #[must_use]77 #[must_use]
71 pub fn map(self, mapper: FuncVal) -> Self {78 pub fn map(self, mapper: FuncVal) -> Self {
237 /// Is this vec supports `.get_cheap()?`244 /// Is this vec supports `.get_cheap()?`
238 pub fn is_cheap(&self) -> bool {245 pub fn is_cheap(&self) -> bool {
239 match self {246 match self {
240 ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) => true,247 ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) | ArrValue::Chars(_) => {
248 true
249 }
241 ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),250 ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),
242 ArrValue::Slice(r) => r.inner.is_cheap(),251 ArrValue::Slice(r) => r.inner.is_cheap(),
243 ArrValue::Reverse(i) => i.0.is_cheap(),252 ArrValue::Reverse(i) => i.0.is_cheap(),
modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -1,15 +1,18 @@
 //! Those implementations are a bit sketchy, as this is mostly performance experiments
 //! of not yet finished nightly rust features
 
-use std::{cell::RefCell, iter, mem::replace};
+use std::{cell::RefCell, iter, mem::replace, rc::Rc};
 
 use jrsonnet_gcmodule::{Cc, Trace};
-use jrsonnet_interner::IBytes;
+use jrsonnet_interner::{IBytes, IStr};
 use jrsonnet_parser::LocExpr;
 
 use super::ArrValue;
 use crate::{
-	error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, val::ThunkValue,
+	error::ErrorKind::InfiniteRecursionDetected,
+	evaluate,
+	function::FuncVal,
+	val::{StrValue, ThunkValue},
 	Context, Error, Result, Thunk, Val,
 };
 
@@ -154,6 +157,69 @@
 }
 
 #[derive(Trace, Debug, Clone)]
+pub struct CharArray(pub Rc<Vec<char>>);
+#[cfg(feature = "nightly")]
+type CharArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;
+#[cfg(feature = "nightly")]
+type CharArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;
+#[cfg(feature = "nightly")]
+type CharArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;
+impl ArrayLike for CharArray {
+	#[cfg(feature = "nightly")]
+	type Iter<'t> = CharArrayIter<'t>;
+	#[cfg(feature = "nightly")]
+	type IterLazy<'t> = CharArrayLazyIter<'t>;
+	#[cfg(feature = "nightly")]
+	type IterCheap<'t> = CharArrayCheapIter<'t>;
+
+	fn len(&self) -> usize {
+		self.0.len()
+	}
+
+	fn get(&self, index: usize) -> Result<Option<Val>> {
+		Ok(self.get_cheap(index))
+	}
+
+	fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
+		self.get_cheap(index).map(Thunk::evaluated)
+	}
+
+	fn get_cheap(&self, index: usize) -> Option<Val> {
+		self.0
+			.get(index)
+			.map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))
+	}
+
+	#[cfg(feature = "nightly")]
+	fn iter(&self) -> CharArrayIter<'_> {
+		self.0
+			.iter()
+			.map(|v| Ok(Val::Str(StrValue::Flat(IStr::from(*v)))))
+	}
+
+	#[cfg(feature = "nightly")]
+	fn iter_lazy(&self) -> CharArrayLazyIter<'_> {
+		self.0
+			.iter()
+			.map(|v| Thunk::evaluated(Val::Str(StrValue::Flat(IStr::from(*v)))))
+	}
+
+	#[cfg(feature = "nightly")]
+	fn iter_cheap(&self) -> Option<CharArrayCheapIter<'_>> {
+		Some(
+			self.0
+				.iter()
+				.map(|v| Val::Str(StrValue::Flat(IStr::from(*v)))),
+		)
+	}
+}
+impl From<CharArray> for ArrValue {
+	fn from(value: CharArray) -> Self {
+		ArrValue::Chars(value)
+	}
+}
+
+#[derive(Trace, Debug, Clone)]
 pub struct BytesArray(pub IBytes);
 #[cfg(feature = "nightly")]
 type BytesArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;
@@ -935,6 +1001,7 @@
 	($t:ident.$m:ident($($ident:ident),*)) => {
 		match $t {
 			Self::Bytes(e) => e.$m($($ident)*),
+			Self::Chars(e) => e.$m($($ident)*),
 			Self::Expr(e) => e.$m($($ident)*),
 			Self::Lazy(e) => e.$m($($ident)*),
 			Self::Eager(e) => e.$m($($ident)*),
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -149,6 +149,12 @@
 	Arr(ArrValue),
 }
 impl IndexableVal {
+	pub fn to_array(self) -> ArrValue {
+		match self {
+			IndexableVal::Str(s) => ArrValue::chars(s.chars()),
+			IndexableVal::Arr(arr) => arr,
+		}
+	}
 	/// Slice the value.
 	///
 	/// # Implementation
modifiedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-interner/src/lib.rs
+++ b/crates/jrsonnet-interner/src/lib.rs
@@ -205,6 +205,12 @@
 		s.as_str().into()
 	}
 }
+impl From<char> for IStr {
+	fn from(value: char) -> Self {
+		let mut buf = [0; 5];
+		Self::from(&*value.encode_utf8(&mut buf))
+	}
+}
 impl From<&[u8]> for IBytes {
 	fn from(v: &[u8]) -> Self {
 		intern_bytes(v)
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -45,8 +45,9 @@
 }
 
 #[builtin]
-pub fn builtin_map(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
-	Ok(arr.map(func))
+pub fn builtin_map(func: FuncVal, arr: IndexableVal) -> ArrValue {
+	let arr = arr.to_array();
+	arr.map(func)
 }
 
 #[builtin]