git.delta.rocks / jrsonnet / refs/commits / ffbc7e982cb4

difftreelog

source

crates/nix-eval/src/macros.rs6.1 KiBsourcehistory
1use serde::Serialize;23use crate::{NixSession, Value};45#[derive(Clone)]6pub struct NixExprBuilder {7	pub(crate) out: String,8	used_fields: Vec<Value>,9}10pub trait AttrSetValue {11	fn to_builder(self) -> NixExprBuilder;12}13trait Primitive {}1415macro_rules! impl_primitive {16	($($t:ty),+) => {17			$(18				impl Primitive for $t {}19			)+20	};21}22impl_primitive!(String, bool, &'static str);2324impl<T> AttrSetValue for T25where26	// Limited by Primitive trait to avoid orphan rules violation with Vec<T: AttrSetValue>27	T: Serialize + Primitive,28{29	fn to_builder(self) -> NixExprBuilder {30		let serialized = nixlike::serialize(self).expect("invalid value for apply");31		NixExprBuilder {32			out: serialized.trim_end().to_owned(),33			used_fields: Vec::new(),34		}35	}36}37impl AttrSetValue for Value {38	fn to_builder(self) -> NixExprBuilder {39		NixExprBuilder {40			out: format!("sess_field_{}", self.session_field_id()),41			used_fields: vec![self],42		}43	}44}45impl<T> AttrSetValue for Vec<T>46where47	T: AttrSetValue,48{49	fn to_builder(self) -> NixExprBuilder {50		let mut builder = NixExprBuilder::list();51		for v in self {52			builder.list_value(NixExprBuilder::attrset_value(v));53		}54		builder.list_end();55		builder56	}57}5859impl NixExprBuilder {60	pub fn object() -> Self {61		NixExprBuilder {62			out: "{ ".to_owned(),63			used_fields: Vec::new(),64		}65	}66	pub fn list() -> Self {67		NixExprBuilder {68			out: "[".to_owned(),69			used_fields: Vec::new(),70		}71	}72	pub fn string(s: &str) -> Self {73		NixExprBuilder {74			out: nixlike::serialize(s)75				.expect("no problems with serializing_string")76				.trim_end()77				.to_owned(),78			used_fields: Vec::new(),79		}80	}81	pub fn attrset_value(v: impl AttrSetValue) -> Self {82		v.to_builder()83	}84	pub fn serialized(v: impl Serialize) -> Self {85		let serialized = nixlike::serialize(v).expect("invalid value for apply");86		Self {87			out: serialized.trim_end().to_owned(),88			used_fields: Vec::new(),89		}90	}91	pub fn value(f: Value) -> Self {92		Self {93			out: format!("sess_field_{}", f.session_field_id()),94			used_fields: vec![f],95		}96	}97	pub fn end_obj(&mut self) {98		self.out.push('}');99	}100	pub fn obj_key(&mut self, name: Self, value: Self) {101		self.out.push_str(r#""${"#);102		self.extend(name);103		self.out.push_str(r#"}" = "#);104		self.extend(value);105		self.out.push_str("; ");106	}107	pub fn list_value(&mut self, value: Self) {108		self.extend(value);109		self.out.push(' ');110	}111	pub fn list_end(&mut self) {112		self.out.push(']');113	}114115	pub fn extend(&mut self, e: Self) {116		self.out.push_str(&e.out);117		self.used_fields.extend(e.used_fields);118	}119120	#[allow(dead_code)]121	pub fn session(&self) -> NixSession {122		let mut session = None;123		for ele in &self.used_fields {124			if session.is_none() {125				session = Some(ele.session());126				continue;127			}128			let session = session.as_ref().expect("checked");129			let ele_sess = ele.session();130			assert!(131				NixSession::ptr_eq(session, &ele_sess),132				"can't mix fields from different session"133			);134		}135		session.expect("expr without fields used")136	}137	#[allow(dead_code)]138	pub fn index_attr(&mut self, s: &str) {139		let escaped = nixlike::serialize(s).expect("string");140		self.out.push('.');141		self.out.push_str(escaped.trim_end());142	}143}144145#[macro_export]146macro_rules! nix_expr_inner {147	//(@munch_object FIXME: value should be arbitrary nix_expr_inner input... Time to write proc-macro?148	(@obj($o:ident) $field:ident$(, $($tt:tt)*)?) => {{149		$o.obj_key(150			NixExprBuilder::string(stringify!($field)),151			NixExprBuilder::attrset_value($field),152		);153		$(nix_expr_inner!(@obj($o) $($tt)*);)?154	}};155	(@obj($o:ident) $field:ident: $v:expr$(, $($tt:tt)*)?) => {{156		$o.obj_key(157			NixExprBuilder::string(stringify!($field)),158			NixExprBuilder::attrset_value($v),159		);160		$(nix_expr_inner!(@obj($o) $($tt)*);)?161	}};162	(@obj($o:ident)) => {{}};163	(Obj { $($tt:tt)* }) => {{164		use $crate::{macros::NixExprBuilder, nix_expr_inner};165		let mut out = NixExprBuilder::object();166		nix_expr_inner!(@obj(out) $($tt)*);167		out.end_obj();168		out169	}};170	(@field($o:ident) . $var:ident $($tt:tt)*) => {{171		$o.index_attr(stringify!($var));172		nix_expr_inner!(@field($o) $($tt)*);173	}};174	(@field($o:ident) [{ $v:expr }] $($tt:tt)*) => {{175		$o.push(Index::attr(&$v));176		nix_expr_inner!(@o($o) $($tt)*);177	}};178	(@field($o:ident) [ $($var:tt)+ ] $($tt:tt)*) => {{179		$o.push(Index::Expr($crate::nix_expr_inner!($($var)+)));180		nix_expr_inner!(@o($o) $($tt)*);181	}};182	(@field($o:ident) ($($var:tt)*) $($tt:tt)*) => {183		$o.push(Index::ExprApply($crate::nix_expr_inner!($($var)+)));184		nix_expr_inner!(@o($o) $($tt)*);185	};186	(@field($o:ident)) => {};187	($field:ident $($tt:tt)*) => {{188		use $crate::{macros::NixExprBuilder, nix_expr_inner};189		// might be used if indexed190		#[allow(unused_mut)]191		let mut out = NixExprBuilder::value($field.clone());192		nix_expr_inner!(@field(out) $($tt)*);193		out194	}};195	($v:literal) => {{196		use $crate::macros::NixExprBuilder;197		NixExprBuilder::string($v)198	}};199	({$v:expr}) => {{200		use $crate::macros::NixExprBuilder;201		NixExprBuilder::serialized(&$v)202	}}203}204#[macro_export]205macro_rules! nix_expr {206	($($tt:tt)+) => {{207		use $crate::{macros::{NixExprBuilder}, Value, nix_expr_inner};208		let expr = nix_expr_inner!($($tt)+);209		Field::new(expr.session(), expr.out)210	}};211}212213#[macro_export]214macro_rules! nix_go {215	(@o($o:ident) . $var:ident $($tt:tt)*) => {{216		$o.push(Index::attr(stringify!($var)));217		nix_go!(@o($o) $($tt)*);218	}};219	(@o($o:ident) [{ $v:expr }] $($tt:tt)*) => {{220		$o.push(Index::attr(&$v));221		nix_go!(@o($o) $($tt)*);222	}};223	(@o($o:ident) [ $($var:tt)+ ] $($tt:tt)*) => {{224		$o.push(Index::Expr($crate::nix_expr_inner!($($var)+)));225		nix_go!(@o($o) $($tt)*);226	}};227	(@o($o:ident) ($($var:tt)*) $($tt:tt)*) => {228		$o.push(Index::ExprApply($crate::nix_expr_inner!($($var)+)));229		nix_go!(@o($o) $($tt)*);230	};231	(@o($o:ident) | $($var:tt)*) => {232		$o.push(Index::Pipe($crate::nix_expr_inner!($($var)+)));233	};234	(@o($o:ident) + $($var:tt)*) => {235		$o.push(Index::Merge($crate::nix_expr_inner!($($var)+)));236	};237	(@o($o:ident)) => {};238	($field:ident $($tt:tt)+) => {{239		use $crate::{nix_go, Index};240		let field = $field.clone();241		let mut out = vec![];242		nix_go!(@o(out) $($tt)*);243		field.select(out).await?244	}}245}246#[macro_export]247macro_rules! nix_go_json {248	($($tt:tt)*) => {{249		$crate::nix_go!($($tt)*).as_json().await?250	}};251}