feat(tvix/value): introduce string representation with &'static str

For cases where the strings are statically known (such as the
oft-occuring name/value), this can be a useful optimisation.

It's also much more convenient in tests.

Change-Id: Ie462b684805bd4986ea5e85ca4bff663bc2d3c3c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6111
Tested-by: BuildkiteCI
Reviewed-by: eta <tvl@eta.st>
This commit is contained in:
Vincent Ambo 2022-08-10 17:53:22 +03:00 committed by tazjin
parent c7ba2dec04
commit 6dc9ca5723
4 changed files with 44 additions and 26 deletions

View file

@ -111,7 +111,7 @@ impl Compiler {
rnix::StrPart::Ast(node) => self.compile(node)?, rnix::StrPart::Ast(node) => self.compile(node)?,
rnix::StrPart::Literal(lit) => { rnix::StrPart::Literal(lit) => {
let idx = self.chunk.add_constant(Value::String(NixString(lit))); let idx = self.chunk.add_constant(Value::String(lit.into()));
self.chunk.add_op(OpCode::OpConstant(idx)); self.chunk.add_op(OpCode::OpConstant(idx));
} }
} }
@ -206,9 +206,9 @@ impl Compiler {
let ident = rnix::types::Ident::cast(fragment).unwrap(); let ident = rnix::types::Ident::cast(fragment).unwrap();
// TODO(tazjin): intern! // TODO(tazjin): intern!
let idx = self let idx = self.chunk.add_constant(Value::String(NixString::Heap(
.chunk ident.as_str().to_string(),
.add_constant(Value::String(NixString(ident.as_str().to_string()))); )));
self.chunk.add_op(OpCode::OpConstant(idx)); self.chunk.add_op(OpCode::OpConstant(idx));
} }

View file

@ -71,14 +71,8 @@ impl NixAttrs {
NixAttrs::KV { name, value } => { NixAttrs::KV { name, value } => {
*self = NixAttrs::Map(BTreeMap::from([ *self = NixAttrs::Map(BTreeMap::from([
( ("name".into(), std::mem::replace(name, Value::Blackhole)),
NixString("name".into()), ("value".into(), std::mem::replace(value, Value::Blackhole)),
std::mem::replace(name, Value::Blackhole),
),
(
NixString("value".into()),
std::mem::replace(value, Value::Blackhole),
),
])); ]));
self.map_mut() self.map_mut()
} }
@ -155,14 +149,14 @@ impl NixAttrs {
fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> { fn attempt_optimise_kv(slice: &mut [Value]) -> Option<NixAttrs> {
let (name_idx, value_idx) = { let (name_idx, value_idx) = {
match (&slice[2], &slice[0]) { match (&slice[2], &slice[0]) {
(Value::String(NixString(s1)), Value::String(NixString(s2))) (Value::String(s1), Value::String(s2))
if (s1 == "name" && s2 == "value") => if (*s1 == NixString::NAME && *s2 == NixString::VALUE) =>
{ {
(3, 1) (3, 1)
} }
(Value::String(NixString(s1)), Value::String(NixString(s2))) (Value::String(s1), Value::String(s2))
if (s1 == "value" && s2 == "name") => if (*s1 == NixString::VALUE && *s2 == NixString::NAME) =>
{ {
(1, 3) (1, 3)
} }
@ -189,7 +183,7 @@ fn set_attr(attrs: &mut NixAttrs, key: NixString, value: Value) -> EvalResult<()
match entry { match entry {
std::collections::btree_map::Entry::Occupied(entry) => { std::collections::btree_map::Entry::Occupied(entry) => {
return Err(Error::DuplicateAttrsKey { return Err(Error::DuplicateAttrsKey {
key: entry.key().0.clone(), key: entry.key().as_str().to_string(),
}) })
} }
@ -254,7 +248,7 @@ fn set_nested_attr(
_ => { _ => {
return Err(Error::DuplicateAttrsKey { return Err(Error::DuplicateAttrsKey {
key: entry.key().0.clone(), key: entry.key().as_str().to_string(),
}) })
} }
}, },

View file

@ -4,16 +4,40 @@ use std::fmt::Display;
/// backing implementations. /// backing implementations.
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct NixString(pub String); pub enum NixString {
Static(&'static str),
Heap(String),
}
impl Display for NixString { impl Display for NixString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.0.as_str()) match self {
NixString::Static(s) => f.write_str(s),
NixString::Heap(s) => f.write_str(s),
}
} }
} }
impl From<&str> for NixString { impl From<&'static str> for NixString {
fn from(s: &str) -> Self { fn from(s: &'static str) -> Self {
NixString(s.to_string()) NixString::Static(s)
}
}
impl From<String> for NixString {
fn from(s: String) -> Self {
NixString::Heap(s)
}
}
impl NixString {
pub const NAME: Self = NixString::Static("name");
pub const VALUE: Self = NixString::Static("value");
pub fn as_str(&self) -> &str {
match self {
NixString::Static(s) => s,
NixString::Heap(s) => s,
}
} }
} }

View file

@ -7,7 +7,7 @@ use crate::{
chunk::Chunk, chunk::Chunk,
errors::{Error, EvalResult}, errors::{Error, EvalResult},
opcode::OpCode, opcode::OpCode,
value::{NixAttrs, NixList, NixString, Value}, value::{NixAttrs, NixList, Value},
}; };
pub struct VM { pub struct VM {
@ -159,10 +159,10 @@ impl VM {
let mut out = String::new(); let mut out = String::new();
for _ in 0..count { for _ in 0..count {
out.push_str(&self.pop().as_string()?.0); out.push_str(&self.pop().as_string()?.as_str());
} }
self.push(Value::String(NixString(out))); self.push(Value::String(out.into()));
Ok(()) Ok(())
} }