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:
		
							parent
							
								
									c7ba2dec04
								
							
						
					
					
						commit
						6dc9ca5723
					
				
					 4 changed files with 44 additions and 26 deletions
				
			
		|  | @ -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)); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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(), | ||||||
|                 }) |                 }) | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue