difftreelog
Merge remote-tracking branch 'origin/feature/importbin' into gcmodule
in: master
11 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/import.rs
+++ b/bindings/jsonnet/src/import.rs
@@ -2,7 +2,7 @@
use jrsonnet_evaluator::{
error::{Error::*, Result},
- throw, EvaluationState, IStr, ImportResolver,
+ throw, EvaluationState, ImportResolver,
};
use std::{
any::Any,
@@ -29,8 +29,7 @@
pub struct CallbackImportResolver {
cb: JsonnetImportCallback,
ctx: *mut c_void,
-
- out: RefCell<HashMap<PathBuf, IStr>>,
+ out: RefCell<HashMap<PathBuf, Vec<u8>>>,
}
impl ImportResolver for CallbackImportResolver {
fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
@@ -75,9 +74,10 @@
Ok(found_here_buf.into())
}
- fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {
+ fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>> {
Ok(self.out.borrow().get(resolved).unwrap().clone())
}
+
unsafe fn as_any(&self) -> &dyn Any {
self
}
@@ -124,12 +124,12 @@
throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))
}
}
- fn load_file_contents(&self, id: &Path) -> Result<IStr> {
+ fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {
let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;
- let mut out = String::new();
- file.read_to_string(&mut out)
- .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;
- Ok(out.into())
+ let mut out = Vec::new();
+ file.read_to_end(&mut out)
+ .map_err(|e| ImportIo(e.to_string()))?;
+ Ok(out)
}
unsafe fn as_any(&self) -> &dyn Any {
self
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -1,5 +1,5 @@
use crate::function::{CallLocation, StaticBuiltin};
-use crate::typed::{Any, PositiveF64, VecVal, M1};
+use crate::typed::{Any, Bytes, PositiveF64, VecVal, M1};
use crate::{
builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},
equals,
@@ -447,17 +447,15 @@
}
#[jrsonnet_macros::builtin]
-fn builtin_encode_utf8(str: IStr) -> Result<VecVal> {
- Ok(VecVal(
- str.bytes()
- .map(|b| Val::Num(b as f64))
- .collect::<Vec<Val>>(),
- ))
+fn builtin_encode_utf8(str: IStr) -> Result<Bytes> {
+ Ok(Bytes(str.bytes().map(|b| b).collect::<Vec<u8>>().into()))
}
#[jrsonnet_macros::builtin]
-fn builtin_decode_utf8(arr: Vec<u8>) -> Result<String> {
- Ok(String::from_utf8(arr).map_err(|_| RuntimeError("bad utf8".into()))?)
+fn builtin_decode_utf8(arr: Bytes) -> Result<IStr> {
+ Ok(std::str::from_utf8(&arr.0)
+ .map_err(|_| RuntimeError("bad utf8".into()))?
+ .into())
}
#[jrsonnet_macros::builtin]
@@ -483,17 +481,21 @@
}
#[jrsonnet_macros::builtin]
-fn builtin_base64(input: Either![Vec<u8>, IStr]) -> Result<String> {
+fn builtin_base64(input: Either![Bytes, IStr]) -> Result<String> {
use Either2::*;
Ok(match input {
- A(a) => base64::encode(a),
+ A(a) => base64::encode(a.0),
B(l) => base64::encode(l.bytes().collect::<Vec<_>>()),
})
}
#[jrsonnet_macros::builtin]
-fn builtin_base64_decode_bytes(input: IStr) -> Result<Vec<u8>> {
- Ok(base64::decode(&input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?)
+fn builtin_base64_decode_bytes(input: IStr) -> Result<Bytes> {
+ Ok(Bytes(
+ base64::decode(&input.as_bytes())
+ .map_err(|_| RuntimeError("bad base64".into()))?
+ .into(),
+ ))
}
#[jrsonnet_macros::builtin]
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -82,6 +82,8 @@
ResolvedFileNotFound(PathBuf),
#[error("imported file is not valid utf-8: {0:?}")]
ImportBadFileUtf8(PathBuf),
+ #[error("import io error: {0}")]
+ ImportIo(String),
#[error("tried to import {1} from {0}, but imports is not supported")]
ImportNotSupported(PathBuf, PathBuf),
#[error(
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -701,5 +701,12 @@
import_location.pop();
Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)
}
+ ImportBin(path) => {
+ let tmp = loc.clone().0;
+ let mut import_location = tmp.to_path_buf();
+ import_location.pop();
+ let bytes = with_state(|s| s.import_file_bin(&import_location, path))?;
+ Val::Arr(ArrValue::Bytes(bytes))
+ }
})
}
crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/import.rs
+++ b/crates/jrsonnet-evaluator/src/import.rs
@@ -5,14 +5,12 @@
use fs::File;
use jrsonnet_interner::IStr;
use std::fs;
-use std::io::Read;
use std::{
any::Any,
- cell::RefCell,
- collections::HashMap,
path::{Path, PathBuf},
rc::Rc,
};
+use std::{convert::TryFrom, io::Read};
/// Implements file resolution logic for `import` and `importStr`
pub trait ImportResolver {
@@ -21,9 +19,19 @@
/// where `${vendor}` is a library path.
fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>>;
+ fn load_file_contents(&self, resolved: &Path) -> Result<Vec<u8>>;
+
/// Reads file from filesystem, should be used only with path received from `resolve_file`
- fn load_file_contents(&self, resolved: &Path) -> Result<IStr>;
+ fn load_file_str(&self, resolved: &Path) -> Result<IStr> {
+ Ok(IStr::try_from(&self.load_file_contents(resolved)? as &[u8])
+ .map_err(|_| ImportBadFileUtf8(resolved.to_path_buf()))?)
+ }
+ /// Reads file from filesystem, should be used only with path received from `resolve_file`
+ fn load_file_bin(&self, resolved: &Path) -> Result<Rc<[u8]>> {
+ Ok(self.load_file_contents(resolved)?.into())
+ }
+
/// # Safety
///
/// For use only in bindings, should not be used elsewhere.
@@ -39,8 +47,7 @@
throw!(ImportNotSupported(from.into(), path.into()))
}
- fn load_file_contents(&self, _resolved: &Path) -> Result<IStr> {
- // Can be only caused by library direct consumer, not by supplied jsonnet
+ fn load_file_contents(&self, _resolved: &Path) -> Result<Vec<u8>> {
panic!("dummy resolver can't load any file")
}
@@ -79,41 +86,12 @@
throw!(ImportFileNotFound(from.to_owned(), path.to_owned()))
}
}
- fn load_file_contents(&self, id: &Path) -> Result<IStr> {
+ fn load_file_contents(&self, id: &Path) -> Result<Vec<u8>> {
let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.to_owned()))?;
- let mut out = String::new();
- file.read_to_string(&mut out)
- .map_err(|_e| ImportBadFileUtf8(id.to_owned()))?;
- Ok(out.into())
- }
- unsafe fn as_any(&self) -> &dyn Any {
- panic!("this resolver can't be used as any")
- }
-}
-
-type ResolutionData = (PathBuf, PathBuf);
-
-/// Caches results of the underlying resolver
-pub struct CachingImportResolver {
- resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<Path>>>>,
- loading_cache: RefCell<HashMap<PathBuf, Result<IStr>>>,
- inner: Box<dyn ImportResolver>,
-}
-impl ImportResolver for CachingImportResolver {
- fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
- self.resolution_cache
- .borrow_mut()
- .entry((from.to_owned(), path.to_owned()))
- .or_insert_with(|| self.inner.resolve_file(from, path))
- .clone()
- }
-
- fn load_file_contents(&self, resolved: &Path) -> Result<IStr> {
- self.loading_cache
- .borrow_mut()
- .entry(resolved.to_owned())
- .or_insert_with(|| self.inner.load_file_contents(resolved))
- .clone()
+ let mut out = Vec::new();
+ file.read_to_end(&mut out)
+ .map_err(|e| ImportIo(e.to_string()))?;
+ Ok(out)
}
unsafe fn as_any(&self) -> &dyn Any {
panic!("this resolver can't be used as any")
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -118,8 +118,9 @@
breakpoints: Breakpoints,
/// Contains file source codes and evaluation results for imports and pretty-printed stacktraces
- files: HashMap<Rc<Path>, FileData>,
- str_files: HashMap<Rc<Path>, IStr>,
+ files: GcHashMap<Rc<Path>, FileData>,
+ str_files: GcHashMap<Rc<Path>, IStr>,
+ bin_files: GcHashMap<Rc<Path>, Rc<[u8]>>,
}
pub struct FileData {
@@ -280,18 +281,26 @@
return self.evaluate_loaded_file_raw(&file_path);
}
}
- let contents = self.load_file_contents(&file_path)?;
+ let contents = self.load_file_str(&file_path)?;
self.add_file(file_path.clone(), contents)?;
self.evaluate_loaded_file_raw(&file_path)
}
pub(crate) fn import_file_str(&self, from: &Path, path: &Path) -> Result<IStr> {
let path = self.resolve_file(from, path)?;
if !self.data().str_files.contains_key(&path) {
- let file_str = self.load_file_contents(&path)?;
+ let file_str = self.load_file_str(&path)?;
self.data_mut().str_files.insert(path.clone(), file_str);
}
Ok(self.data().str_files.get(&path).cloned().unwrap())
}
+ pub(crate) fn import_file_bin(&self, from: &Path, path: &Path) -> Result<Rc<[u8]>> {
+ let path = self.resolve_file(from, path)?;
+ if !self.data().bin_files.contains_key(&path) {
+ let file_bin = self.load_file_bin(&path)?;
+ self.data_mut().bin_files.insert(path.clone(), file_bin);
+ }
+ Ok(self.data().bin_files.get(&path).cloned().unwrap())
+ }
fn evaluate_loaded_file_raw(&self, name: &Path) -> Result<Val> {
let expr: LocExpr = {
@@ -607,8 +616,11 @@
pub fn resolve_file(&self, from: &Path, path: &Path) -> Result<Rc<Path>> {
self.settings().import_resolver.resolve_file(from, path)
}
- pub fn load_file_contents(&self, path: &Path) -> Result<IStr> {
- self.settings().import_resolver.load_file_contents(path)
+ pub fn load_file_str(&self, path: &Path) -> Result<IStr> {
+ self.settings().import_resolver.load_file_str(path)
+ }
+ pub fn load_file_bin(&self, path: &Path) -> Result<Rc<[u8]>> {
+ self.settings().import_resolver.load_file_bin(path)
}
pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {
@@ -687,7 +699,6 @@
primitive_equals, EvaluationState,
};
use gcmodule::{Cc, Trace};
- use jrsonnet_interner::IStr;
use jrsonnet_parser::*;
use std::{
path::{Path, PathBuf},
@@ -1204,19 +1215,23 @@
Ok(())
}
- struct TestImportResolver(IStr);
+ struct TestImportResolver(Vec<u8>);
impl crate::import::ImportResolver for TestImportResolver {
fn resolve_file(&self, _: &Path, _: &Path) -> crate::error::Result<Rc<Path>> {
Ok(PathBuf::from("/test").into())
}
- fn load_file_contents(&self, _: &Path) -> crate::error::Result<IStr> {
+ fn load_file_contents(&self, _: &Path) -> crate::error::Result<Vec<u8>> {
Ok(self.0.clone())
}
unsafe fn as_any(&self) -> &dyn std::any::Any {
panic!()
}
+
+ fn load_file_bin(&self, _resolved: &Path) -> crate::error::Result<Rc<[u8]>> {
+ panic!()
+ }
}
#[test]
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::convert::{TryFrom, TryInto};23use gcmodule::Cc;4use jrsonnet_interner::IStr;5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};78use crate::{9 error::{Error::*, LocError, Result},10 throw,11 typed::CheckType,12 ArrValue, FuncDesc, FuncVal, IndexableVal, ObjValue, ObjValueBuilder, Val,13};1415pub trait TypedObj: Typed {16 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;17 fn parse(obj: &ObjValue) -> Result<Self>;18 fn into_object(self) -> Result<ObjValue> {19 let mut builder = ObjValueBuilder::new();20 self.serialize(&mut builder)?;21 Ok(builder.build())22 }23}2425pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {26 const TYPE: &'static ComplexValType;27}2829macro_rules! impl_int {30 ($($ty:ty)*) => {$(31 impl Typed for $ty {32 const TYPE: &'static ComplexValType =33 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));34 }35 impl TryFrom<Val> for $ty {36 type Error = LocError;3738 fn try_from(value: Val) -> Result<Self> {39 <Self as Typed>::TYPE.check(&value)?;40 match value {41 Val::Num(n) => {42 if n.trunc() != n {43 throw!(RuntimeError(44 format!(45 "cannot convert number with fractional part to {}",46 stringify!($ty)47 )48 .into()49 ))50 }51 Ok(n as Self)52 }53 _ => unreachable!(),54 }55 }56 }57 impl TryFrom<$ty> for Val {58 type Error = LocError;5960 fn try_from(value: $ty) -> Result<Self> {61 Ok(Self::Num(value as f64))62 }63 }64 )*};65}6667impl_int!(i8 u8 i16 u16 i32 u32);6869impl Typed for f64 {70 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);71}72impl TryFrom<Val> for f64 {73 type Error = LocError;7475 fn try_from(value: Val) -> Result<Self> {76 <Self as Typed>::TYPE.check(&value)?;77 match value {78 Val::Num(n) => Ok(n),79 _ => unreachable!(),80 }81 }82}83impl TryFrom<f64> for Val {84 type Error = LocError;8586 fn try_from(value: f64) -> Result<Self> {87 Ok(Self::Num(value))88 }89}9091pub struct PositiveF64(pub f64);92impl Typed for PositiveF64 {93 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);94}95impl TryFrom<Val> for PositiveF64 {96 type Error = LocError;9798 fn try_from(value: Val) -> Result<Self> {99 <Self as Typed>::TYPE.check(&value)?;100 match value {101 Val::Num(n) => Ok(Self(n)),102 _ => unreachable!(),103 }104 }105}106impl TryFrom<PositiveF64> for Val {107 type Error = LocError;108109 fn try_from(value: PositiveF64) -> Result<Self> {110 Ok(Self::Num(value.0))111 }112}113114impl Typed for usize {115 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility116 const TYPE: &'static ComplexValType =117 &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));118}119impl TryFrom<Val> for usize {120 type Error = LocError;121122 fn try_from(value: Val) -> Result<Self> {123 <Self as Typed>::TYPE.check(&value)?;124 match value {125 Val::Num(n) => {126 if n.trunc() != n {127 throw!(RuntimeError(128 "cannot convert number with fractional part to usize".into()129 ))130 }131 Ok(n as Self)132 }133 _ => unreachable!(),134 }135 }136}137impl TryFrom<usize> for Val {138 type Error = LocError;139140 fn try_from(value: usize) -> Result<Self> {141 if value > u32::MAX as usize {142 throw!(RuntimeError("number is too large".into()))143 }144 Ok(Self::Num(value as f64))145 }146}147148impl Typed for IStr {149 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);150}151impl TryFrom<Val> for IStr {152 type Error = LocError;153154 fn try_from(value: Val) -> Result<Self> {155 <Self as Typed>::TYPE.check(&value)?;156 match value {157 Val::Str(s) => Ok(s),158 _ => unreachable!(),159 }160 }161}162impl TryFrom<IStr> for Val {163 type Error = LocError;164165 fn try_from(value: IStr) -> Result<Self> {166 Ok(Self::Str(value))167 }168}169170impl Typed for String {171 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);172}173impl TryFrom<Val> for String {174 type Error = LocError;175176 fn try_from(value: Val) -> Result<Self> {177 <Self as Typed>::TYPE.check(&value)?;178 match value {179 Val::Str(s) => Ok(s.to_string()),180 _ => unreachable!(),181 }182 }183}184impl TryFrom<String> for Val {185 type Error = LocError;186187 fn try_from(value: String) -> Result<Self> {188 Ok(Self::Str(value.into()))189 }190}191192impl Typed for char {193 const TYPE: &'static ComplexValType = &ComplexValType::Char;194}195impl TryFrom<Val> for char {196 type Error = LocError;197198 fn try_from(value: Val) -> Result<Self> {199 <Self as Typed>::TYPE.check(&value)?;200 match value {201 Val::Str(s) => Ok(s.chars().next().unwrap()),202 _ => unreachable!(),203 }204 }205}206impl TryFrom<char> for Val {207 type Error = LocError;208209 fn try_from(value: char) -> Result<Self> {210 Ok(Self::Str(value.to_string().into()))211 }212}213214impl<T> Typed for Vec<T>215where216 T: Typed,217 T: TryFrom<Val, Error = LocError>,218 T: TryInto<Val, Error = LocError>,219{220 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);221}222impl<T> TryFrom<Val> for Vec<T>223where224 T: Typed,225 T: TryFrom<Val, Error = LocError>,226 T: TryInto<Val, Error = LocError>,227{228 type Error = LocError;229230 fn try_from(value: Val) -> Result<Self> {231 <Self as Typed>::TYPE.check(&value)?;232 match value {233 Val::Arr(a) => {234 let mut o = Self::with_capacity(a.len());235 for i in a.iter() {236 o.push(T::try_from(i?)?);237 }238 Ok(o)239 }240 _ => unreachable!(),241 }242 }243}244impl<T> TryFrom<Vec<T>> for Val245where246 T: Typed,247 T: TryFrom<Self, Error = LocError>,248 T: TryInto<Self, Error = LocError>,249{250 type Error = LocError;251252 fn try_from(value: Vec<T>) -> Result<Self> {253 let mut o = Vec::with_capacity(value.len());254 for i in value {255 o.push(i.try_into()?);256 }257 Ok(Self::Arr(o.into()))258 }259}260261/// To be used in Vec<Any>262/// Regular Val can't be used here, because it has wrong TryFrom::Error type263#[derive(Clone)]264pub struct Any(pub Val);265266impl Typed for Any {267 const TYPE: &'static ComplexValType = &ComplexValType::Any;268}269impl TryFrom<Val> for Any {270 type Error = LocError;271272 fn try_from(value: Val) -> Result<Self> {273 Ok(Self(value))274 }275}276impl TryFrom<Any> for Val {277 type Error = LocError;278279 fn try_from(value: Any) -> Result<Self> {280 Ok(value.0)281 }282}283284/// Specialization, provides faster TryFrom<VecVal> for Val285pub struct VecVal(pub Vec<Val>);286287impl Typed for VecVal {288 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);289}290impl TryFrom<Val> for VecVal {291 type Error = LocError;292293 fn try_from(value: Val) -> Result<Self> {294 <Self as Typed>::TYPE.check(&value)?;295 match value {296 Val::Arr(a) => Ok(Self(a.evaluated()?.to_vec())),297 _ => unreachable!(),298 }299 }300}301impl TryFrom<VecVal> for Val {302 type Error = LocError;303304 fn try_from(value: VecVal) -> Result<Self> {305 Ok(Self::Arr(value.0.into()))306 }307}308309pub struct M1;310impl Typed for M1 {311 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));312}313impl TryFrom<Val> for M1 {314 type Error = LocError;315316 fn try_from(value: Val) -> Result<Self> {317 <Self as Typed>::TYPE.check(&value)?;318 Ok(Self)319 }320}321impl TryFrom<M1> for Val {322 type Error = LocError;323324 fn try_from(_: M1) -> Result<Self> {325 Ok(Self::Num(-1.0))326 }327}328329macro_rules! decl_either {330 ($($name: ident, $($id: ident)*);*) => {$(331 pub enum $name<$($id),*> {332 $($id($id)),*333 }334 impl<$($id),*> Typed for $name<$($id),*>335 where336 $($id: Typed,)*337 {338 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);339 }340 impl<$($id),*> TryFrom<Val> for $name<$($id),*>341 where342 $($id: Typed,)*343 {344 type Error = LocError;345346 fn try_from(value: Val) -> Result<Self> {347 $(348 if $id::TYPE.check(&value).is_ok() {349 $id::try_from(value).map(Self::$id)350 } else351 )* {352 <Self as Typed>::TYPE.check(&value)?;353 unreachable!()354 }355 }356 }357 impl<$($id),*> TryFrom<$name<$($id),*>> for Val358 where359 $($id: Typed,)*360 {361 type Error = LocError;362 fn try_from(value: $name<$($id),*>) -> Result<Self> {363 match value {$(364 $name::$id(v) => v.try_into()365 ),*}366 }367 }368 )*}369}370decl_either!(371 Either1, A;372 Either2, A B;373 Either3, A B C;374 Either4, A B C D;375 Either5, A B C D E;376 Either6, A B C D E F;377 Either7, A B C D E F G378);379#[macro_export]380macro_rules! Either {381 ($a:ty) => {Either1<$a>};382 ($a:ty, $b:ty) => {Either2<$a, $b>};383 ($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};384 ($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};385 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};386 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};387 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};388}389390pub type MyType = Either![u32, f64, String];391392impl Typed for ArrValue {393 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);394}395impl TryFrom<Val> for ArrValue {396 type Error = LocError;397398 fn try_from(value: Val) -> Result<Self> {399 <Self as Typed>::TYPE.check(&value)?;400 match value {401 Val::Arr(a) => Ok(a),402 _ => unreachable!(),403 }404 }405}406impl TryFrom<ArrValue> for Val {407 type Error = LocError;408409 fn try_from(value: ArrValue) -> Result<Self> {410 Ok(Self::Arr(value))411 }412}413414impl Typed for FuncVal {415 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);416}417impl TryFrom<Val> for FuncVal {418 type Error = LocError;419420 fn try_from(value: Val) -> Result<Self> {421 <Self as Typed>::TYPE.check(&value)?;422 match value {423 Val::Func(a) => Ok(a),424 _ => unreachable!(),425 }426 }427}428impl TryFrom<FuncVal> for Val {429 type Error = LocError;430431 fn try_from(value: FuncVal) -> Result<Self> {432 Ok(Self::Func(value))433 }434}435436impl Typed for Cc<FuncDesc> {437 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);438}439impl TryFrom<Val> for Cc<FuncDesc> {440 type Error = LocError;441442 fn try_from(value: Val) -> Result<Self, Self::Error> {443 <Self as Typed>::TYPE.check(&value)?;444 match value {445 Val::Func(FuncVal::Normal(desc)) => Ok(desc),446 Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),447 _ => unreachable!(),448 }449 }450}451impl TryFrom<Cc<FuncDesc>> for Val {452 type Error = LocError;453454 fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {455 Ok(Self::Func(FuncVal::Normal(value)))456 }457}458459impl Typed for ObjValue {460 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);461}462impl TryFrom<Val> for ObjValue {463 type Error = LocError;464465 fn try_from(value: Val) -> Result<Self> {466 <Self as Typed>::TYPE.check(&value)?;467 match value {468 Val::Obj(a) => Ok(a),469 _ => unreachable!(),470 }471 }472}473impl TryFrom<ObjValue> for Val {474 type Error = LocError;475476 fn try_from(value: ObjValue) -> Result<Self> {477 Ok(Self::Obj(value))478 }479}480481impl Typed for bool {482 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);483}484impl TryFrom<Val> for bool {485 type Error = LocError;486487 fn try_from(value: Val) -> Result<Self> {488 <Self as Typed>::TYPE.check(&value)?;489 match value {490 Val::Bool(a) => Ok(a),491 _ => unreachable!(),492 }493 }494}495impl TryFrom<bool> for Val {496 type Error = LocError;497498 fn try_from(value: bool) -> Result<Self> {499 Ok(Self::Bool(value))500 }501}502503impl Typed for IndexableVal {504 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[505 &ComplexValType::Simple(ValType::Arr),506 &ComplexValType::Simple(ValType::Str),507 ]);508}509impl TryFrom<Val> for IndexableVal {510 type Error = LocError;511512 fn try_from(value: Val) -> Result<Self> {513 <Self as Typed>::TYPE.check(&value)?;514 value.into_indexable()515 }516}517impl TryFrom<IndexableVal> for Val {518 type Error = LocError;519520 fn try_from(value: IndexableVal) -> Result<Self> {521 match value {522 IndexableVal::Str(s) => Ok(Self::Str(s)),523 IndexableVal::Arr(a) => Ok(Self::Arr(a)),524 }525 }526}527528pub struct Null;529impl Typed for Null {530 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);531}532impl TryFrom<Val> for Null {533 type Error = LocError;534535 fn try_from(value: Val) -> Result<Self> {536 <Self as Typed>::TYPE.check(&value)?;537 Ok(Self)538 }539}540impl TryFrom<Null> for Val {541 type Error = LocError;542543 fn try_from(_: Null) -> Result<Self> {544 Ok(Self::Null)545 }546}1use std::{2 convert::{TryFrom, TryInto},3 rc::Rc,4};56use gcmodule::Cc;7use jrsonnet_interner::IStr;8pub use jrsonnet_macros::Typed;9use jrsonnet_types::{ComplexValType, ValType};1011use crate::{12 error::{Error::*, LocError, Result},13 throw,14 typed::CheckType,15 ArrValue, FuncDesc, FuncVal, IndexableVal, ObjValue, ObjValueBuilder, Val,16};1718pub trait TypedObj: Typed {19 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;20 fn parse(obj: &ObjValue) -> Result<Self>;21 fn into_object(self) -> Result<ObjValue> {22 let mut builder = ObjValueBuilder::new();23 self.serialize(&mut builder)?;24 Ok(builder.build())25 }26}2728pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {29 const TYPE: &'static ComplexValType;30}3132macro_rules! impl_int {33 ($($ty:ty)*) => {$(34 impl Typed for $ty {35 const TYPE: &'static ComplexValType =36 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));37 }38 impl TryFrom<Val> for $ty {39 type Error = LocError;4041 fn try_from(value: Val) -> Result<Self> {42 <Self as Typed>::TYPE.check(&value)?;43 match value {44 Val::Num(n) => {45 if n.trunc() != n {46 throw!(RuntimeError(47 format!(48 "cannot convert number with fractional part to {}",49 stringify!($ty)50 )51 .into()52 ))53 }54 Ok(n as Self)55 }56 _ => unreachable!(),57 }58 }59 }60 impl TryFrom<$ty> for Val {61 type Error = LocError;6263 fn try_from(value: $ty) -> Result<Self> {64 Ok(Self::Num(value as f64))65 }66 }67 )*};68}6970impl_int!(i8 u8 i16 u16 i32 u32);7172impl Typed for f64 {73 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);74}75impl TryFrom<Val> for f64 {76 type Error = LocError;7778 fn try_from(value: Val) -> Result<Self> {79 <Self as Typed>::TYPE.check(&value)?;80 match value {81 Val::Num(n) => Ok(n),82 _ => unreachable!(),83 }84 }85}86impl TryFrom<f64> for Val {87 type Error = LocError;8889 fn try_from(value: f64) -> Result<Self> {90 Ok(Self::Num(value))91 }92}9394pub struct PositiveF64(pub f64);95impl Typed for PositiveF64 {96 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);97}98impl TryFrom<Val> for PositiveF64 {99 type Error = LocError;100101 fn try_from(value: Val) -> Result<Self> {102 <Self as Typed>::TYPE.check(&value)?;103 match value {104 Val::Num(n) => Ok(Self(n)),105 _ => unreachable!(),106 }107 }108}109impl TryFrom<PositiveF64> for Val {110 type Error = LocError;111112 fn try_from(value: PositiveF64) -> Result<Self> {113 Ok(Self::Num(value.0))114 }115}116117impl Typed for usize {118 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility119 const TYPE: &'static ComplexValType =120 &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));121}122impl TryFrom<Val> for usize {123 type Error = LocError;124125 fn try_from(value: Val) -> Result<Self> {126 <Self as Typed>::TYPE.check(&value)?;127 match value {128 Val::Num(n) => {129 if n.trunc() != n {130 throw!(RuntimeError(131 "cannot convert number with fractional part to usize".into()132 ))133 }134 Ok(n as Self)135 }136 _ => unreachable!(),137 }138 }139}140impl TryFrom<usize> for Val {141 type Error = LocError;142143 fn try_from(value: usize) -> Result<Self> {144 if value > u32::MAX as usize {145 throw!(RuntimeError("number is too large".into()))146 }147 Ok(Self::Num(value as f64))148 }149}150151impl Typed for IStr {152 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);153}154impl TryFrom<Val> for IStr {155 type Error = LocError;156157 fn try_from(value: Val) -> Result<Self> {158 <Self as Typed>::TYPE.check(&value)?;159 match value {160 Val::Str(s) => Ok(s),161 _ => unreachable!(),162 }163 }164}165impl TryFrom<IStr> for Val {166 type Error = LocError;167168 fn try_from(value: IStr) -> Result<Self> {169 Ok(Self::Str(value))170 }171}172173impl Typed for String {174 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);175}176impl TryFrom<Val> for String {177 type Error = LocError;178179 fn try_from(value: Val) -> Result<Self> {180 <Self as Typed>::TYPE.check(&value)?;181 match value {182 Val::Str(s) => Ok(s.to_string()),183 _ => unreachable!(),184 }185 }186}187impl TryFrom<String> for Val {188 type Error = LocError;189190 fn try_from(value: String) -> Result<Self> {191 Ok(Self::Str(value.into()))192 }193}194195impl Typed for char {196 const TYPE: &'static ComplexValType = &ComplexValType::Char;197}198impl TryFrom<Val> for char {199 type Error = LocError;200201 fn try_from(value: Val) -> Result<Self> {202 <Self as Typed>::TYPE.check(&value)?;203 match value {204 Val::Str(s) => Ok(s.chars().next().unwrap()),205 _ => unreachable!(),206 }207 }208}209impl TryFrom<char> for Val {210 type Error = LocError;211212 fn try_from(value: char) -> Result<Self> {213 Ok(Self::Str(value.to_string().into()))214 }215}216217impl<T> Typed for Vec<T>218where219 T: Typed,220 T: TryFrom<Val, Error = LocError>,221 T: TryInto<Val, Error = LocError>,222{223 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);224}225impl<T> TryFrom<Val> for Vec<T>226where227 T: Typed,228 T: TryFrom<Val, Error = LocError>,229 T: TryInto<Val, Error = LocError>,230{231 type Error = LocError;232233 fn try_from(value: Val) -> Result<Self> {234 <Self as Typed>::TYPE.check(&value)?;235 match value {236 Val::Arr(a) => {237 let mut o = Self::with_capacity(a.len());238 for i in a.iter() {239 o.push(T::try_from(i?)?);240 }241 Ok(o)242 }243 _ => unreachable!(),244 }245 }246}247impl<T> TryFrom<Vec<T>> for Val248where249 T: Typed,250 T: TryFrom<Self, Error = LocError>,251 T: TryInto<Self, Error = LocError>,252{253 type Error = LocError;254255 fn try_from(value: Vec<T>) -> Result<Self> {256 let mut o = Vec::with_capacity(value.len());257 for i in value {258 o.push(i.try_into()?);259 }260 Ok(Self::Arr(o.into()))261 }262}263264/// To be used in Vec<Any>265/// Regular Val can't be used here, because it has wrong TryFrom::Error type266#[derive(Clone)]267pub struct Any(pub Val);268269impl Typed for Any {270 const TYPE: &'static ComplexValType = &ComplexValType::Any;271}272impl TryFrom<Val> for Any {273 type Error = LocError;274275 fn try_from(value: Val) -> Result<Self> {276 Ok(Self(value))277 }278}279impl TryFrom<Any> for Val {280 type Error = LocError;281282 fn try_from(value: Any) -> Result<Self> {283 Ok(value.0)284 }285}286287/// Specialization, provides faster TryFrom<VecVal> for Val288pub struct VecVal(pub Vec<Val>);289290impl Typed for VecVal {291 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);292}293impl TryFrom<Val> for VecVal {294 type Error = LocError;295296 fn try_from(value: Val) -> Result<Self> {297 <Self as Typed>::TYPE.check(&value)?;298 match value {299 Val::Arr(a) => Ok(Self(a.evaluated()?.to_vec())),300 _ => unreachable!(),301 }302 }303}304impl TryFrom<VecVal> for Val {305 type Error = LocError;306307 fn try_from(value: VecVal) -> Result<Self> {308 Ok(Self::Arr(value.0.into()))309 }310}311312/// Specialization313pub struct Bytes(pub Rc<[u8]>);314315impl Typed for Bytes {316 const TYPE: &'static ComplexValType =317 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));318}319impl TryFrom<Val> for Bytes {320 type Error = LocError;321322 fn try_from(value: Val) -> Result<Self> {323 match value {324 Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),325 _ => {326 <Self as Typed>::TYPE.check(&value)?;327 match value {328 Val::Arr(a) => {329 let mut out = Vec::with_capacity(a.len());330 for e in a.iter() {331 let r = e?;332 out.push(u8::try_from(r)?);333 }334 Ok(Self(out.into()))335 }336 _ => unreachable!(),337 }338 }339 }340 }341}342impl TryFrom<Bytes> for Val {343 type Error = LocError;344345 fn try_from(value: Bytes) -> Result<Self> {346 Ok(Val::Arr(ArrValue::Bytes(value.0)))347 }348}349350pub struct M1;351impl Typed for M1 {352 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));353}354impl TryFrom<Val> for M1 {355 type Error = LocError;356357 fn try_from(value: Val) -> Result<Self> {358 <Self as Typed>::TYPE.check(&value)?;359 Ok(Self)360 }361}362impl TryFrom<M1> for Val {363 type Error = LocError;364365 fn try_from(_: M1) -> Result<Self> {366 Ok(Self::Num(-1.0))367 }368}369370macro_rules! decl_either {371 ($($name: ident, $($id: ident)*);*) => {$(372 pub enum $name<$($id),*> {373 $($id($id)),*374 }375 impl<$($id),*> Typed for $name<$($id),*>376 where377 $($id: Typed,)*378 {379 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);380 }381 impl<$($id),*> TryFrom<Val> for $name<$($id),*>382 where383 $($id: Typed,)*384 {385 type Error = LocError;386387 fn try_from(value: Val) -> Result<Self> {388 $(389 if $id::TYPE.check(&value).is_ok() {390 $id::try_from(value).map(Self::$id)391 } else392 )* {393 <Self as Typed>::TYPE.check(&value)?;394 unreachable!()395 }396 }397 }398 impl<$($id),*> TryFrom<$name<$($id),*>> for Val399 where400 $($id: Typed,)*401 {402 type Error = LocError;403 fn try_from(value: $name<$($id),*>) -> Result<Self> {404 match value {$(405 $name::$id(v) => v.try_into()406 ),*}407 }408 }409 )*}410}411decl_either!(412 Either1, A;413 Either2, A B;414 Either3, A B C;415 Either4, A B C D;416 Either5, A B C D E;417 Either6, A B C D E F;418 Either7, A B C D E F G419);420#[macro_export]421macro_rules! Either {422 ($a:ty) => {Either1<$a>};423 ($a:ty, $b:ty) => {Either2<$a, $b>};424 ($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};425 ($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};426 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};427 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};428 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};429}430431pub type MyType = Either![u32, f64, String];432433impl Typed for ArrValue {434 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);435}436impl TryFrom<Val> for ArrValue {437 type Error = LocError;438439 fn try_from(value: Val) -> Result<Self> {440 <Self as Typed>::TYPE.check(&value)?;441 match value {442 Val::Arr(a) => Ok(a),443 _ => unreachable!(),444 }445 }446}447impl TryFrom<ArrValue> for Val {448 type Error = LocError;449450 fn try_from(value: ArrValue) -> Result<Self> {451 Ok(Self::Arr(value))452 }453}454455impl Typed for FuncVal {456 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);457}458impl TryFrom<Val> for FuncVal {459 type Error = LocError;460461 fn try_from(value: Val) -> Result<Self> {462 <Self as Typed>::TYPE.check(&value)?;463 match value {464 Val::Func(a) => Ok(a),465 _ => unreachable!(),466 }467 }468}469impl TryFrom<FuncVal> for Val {470 type Error = LocError;471472 fn try_from(value: FuncVal) -> Result<Self> {473 Ok(Self::Func(value))474 }475}476477impl Typed for Cc<FuncDesc> {478 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);479}480impl TryFrom<Val> for Cc<FuncDesc> {481 type Error = LocError;482483 fn try_from(value: Val) -> Result<Self, Self::Error> {484 <Self as Typed>::TYPE.check(&value)?;485 match value {486 Val::Func(FuncVal::Normal(desc)) => Ok(desc),487 Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),488 _ => unreachable!(),489 }490 }491}492impl TryFrom<Cc<FuncDesc>> for Val {493 type Error = LocError;494495 fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {496 Ok(Self::Func(FuncVal::Normal(value)))497 }498}499500impl Typed for ObjValue {501 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);502}503impl TryFrom<Val> for ObjValue {504 type Error = LocError;505506 fn try_from(value: Val) -> Result<Self> {507 <Self as Typed>::TYPE.check(&value)?;508 match value {509 Val::Obj(a) => Ok(a),510 _ => unreachable!(),511 }512 }513}514impl TryFrom<ObjValue> for Val {515 type Error = LocError;516517 fn try_from(value: ObjValue) -> Result<Self> {518 Ok(Self::Obj(value))519 }520}521522impl Typed for bool {523 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);524}525impl TryFrom<Val> for bool {526 type Error = LocError;527528 fn try_from(value: Val) -> Result<Self> {529 <Self as Typed>::TYPE.check(&value)?;530 match value {531 Val::Bool(a) => Ok(a),532 _ => unreachable!(),533 }534 }535}536impl TryFrom<bool> for Val {537 type Error = LocError;538539 fn try_from(value: bool) -> Result<Self> {540 Ok(Self::Bool(value))541 }542}543544impl Typed for IndexableVal {545 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[546 &ComplexValType::Simple(ValType::Arr),547 &ComplexValType::Simple(ValType::Str),548 ]);549}550impl TryFrom<Val> for IndexableVal {551 type Error = LocError;552553 fn try_from(value: Val) -> Result<Self> {554 <Self as Typed>::TYPE.check(&value)?;555 value.into_indexable()556 }557}558impl TryFrom<IndexableVal> for Val {559 type Error = LocError;560561 fn try_from(value: IndexableVal) -> Result<Self> {562 match value {563 IndexableVal::Str(s) => Ok(Self::Str(s)),564 IndexableVal::Arr(a) => Ok(Self::Arr(a)),565 }566 }567}568569pub struct Null;570impl Typed for Null {571 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);572}573impl TryFrom<Val> for Null {574 type Error = LocError;575576 fn try_from(value: Val) -> Result<Self> {577 <Self as Typed>::TYPE.check(&value)?;578 Ok(Self)579 }580}581impl TryFrom<Null> for Val {582 type Error = LocError;583584 fn try_from(_: Null) -> Result<Self> {585 Ok(Self::Null)586 }587}crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -174,6 +174,7 @@
#[derive(Debug, Clone, Trace)]
#[force_tracking]
pub enum ArrValue {
+ Bytes(#[skip_trace] Rc<[u8]>),
Lazy(Cc<Vec<LazyVal>>),
Eager(Cc<Vec<Val>>),
Extended(Box<(Self, Self)>),
@@ -185,6 +186,7 @@
pub fn len(&self) -> usize {
match self {
+ Self::Bytes(i) => i.len(),
Self::Lazy(l) => l.len(),
Self::Eager(e) => e.len(),
Self::Extended(v) => v.0.len() + v.1.len(),
@@ -197,6 +199,9 @@
pub fn get(&self, index: usize) -> Result<Option<Val>> {
match self {
+ Self::Bytes(i) => i
+ .get(index)
+ .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),
Self::Lazy(vec) => {
if let Some(v) = vec.get(index) {
Ok(Some(v.evaluate()?))
@@ -218,6 +223,9 @@
pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {
match self {
+ Self::Bytes(i) => i
+ .get(index)
+ .map(|b| LazyVal::new_resolved(Val::Num(*b as f64))),
Self::Lazy(vec) => vec.get(index).cloned(),
Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),
Self::Extended(v) => {
@@ -233,6 +241,13 @@
pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {
Ok(match self {
+ Self::Bytes(i) => {
+ let mut out = Vec::with_capacity(i.len());
+ for v in i.iter() {
+ out.push(Val::Num(*v as f64));
+ }
+ Cc::new(out)
+ }
Self::Lazy(vec) => {
let mut out = Vec::with_capacity(vec.len());
for item in vec.iter() {
@@ -253,6 +268,7 @@
pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
(0..self.len()).map(move |idx| match self {
+ Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),
Self::Lazy(l) => l[idx].evaluate(),
Self::Eager(e) => Ok(e[idx].clone()),
Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),
@@ -261,6 +277,7 @@
pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {
(0..self.len()).map(move |idx| match self {
+ Self::Bytes(b) => LazyVal::new_resolved(Val::Num(b[idx] as f64)),
Self::Lazy(l) => l[idx].clone(),
Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),
Self::Extended(_) => self.get_lazy(idx).unwrap(),
@@ -269,6 +286,11 @@
pub fn reversed(self) -> Self {
match self {
+ Self::Bytes(b) => {
+ let mut out = b.to_vec();
+ out.reverse();
+ Self::Bytes(out.into())
+ }
Self::Lazy(vec) => {
let mut out = (&vec as &Vec<_>).clone();
out.reverse();
crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-interner/src/lib.rs
+++ b/crates/jrsonnet-interner/src/lib.rs
@@ -4,10 +4,12 @@
use std::{
borrow::Cow,
cell::RefCell,
+ convert::TryFrom,
fmt::{self, Display},
hash::{BuildHasherDefault, Hash, Hasher},
ops::Deref,
rc::Rc,
+ str::Utf8Error,
};
#[derive(Clone, PartialOrd, Ord, Eq)]
@@ -85,6 +87,15 @@
}
}
+impl TryFrom<&[u8]> for IStr {
+ type Error = Utf8Error;
+
+ fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
+ let str = std::str::from_utf8(value)?;
+ Ok(str.into())
+ }
+}
+
impl From<String> for IStr {
fn from(str: String) -> Self {
(&str as &str).into()
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -285,6 +285,8 @@
Import(PathBuf),
/// importStr "file.txt"
ImportStr(PathBuf),
+ /// importBin "file.txt"
+ ImportBin(PathBuf),
/// error "I'm broken"
ErrorStmt(LocExpr),
/// a(b, c)
crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -53,7 +53,7 @@
rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.parse().map_err(|_| "<number>") }} / expected!("<number>")
/// Reserved word followed by any non-alphanumberic
- rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()
+ rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()
rule id() = quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")
rule keyword(id: &'static str) -> ()
@@ -218,6 +218,7 @@
/ array_comp_expr(s)
/ keyword("importstr") _ path:string() {Expr::ImportStr(PathBuf::from(path))}
+ / keyword("importbin") _ path:string() {Expr::ImportBin(PathBuf::from(path))}
/ keyword("import") _ path:string() {Expr::Import(PathBuf::from(path))}
/ var_expr(s)