build_info_proc/format/value/
mod.rs

1use std::{
2	any::{type_name, Any},
3	fmt::Debug,
4};
5
6use anyhow::anyhow;
7use num_bigint::BigInt;
8use num_traits::ToPrimitive;
9
10use super::Type;
11
12mod bool;
13mod char;
14mod int;
15mod option;
16mod string;
17mod vec;
18
19mod chrono;
20mod semver;
21
22mod build_info;
23mod compiler_channel;
24mod compiler_info;
25mod cpu_info;
26mod crate_info;
27mod endianness;
28mod git_info;
29mod optimization_level;
30mod target_info;
31mod version_control;
32
33mod functions;
34pub(crate) use functions::call_function;
35
36mod macros;
37pub(crate) use macros::call_macro;
38
39pub(crate) trait Value: Debug {
40	fn call_base(&self, func: &str, args: &[Box<dyn Value>]) -> anyhow::Result<Box<dyn Value>> {
41		match func {
42			OP_FIELD_ACCESS => {
43				let field = as_field_name(args);
44				Err(anyhow!(
45					"The field {} does not exist for objects of type {}",
46					field,
47					self.get_type()
48				))
49			}
50			OP_TUPLE_INDEX => Err(anyhow!("Type {} cannot be tuple-indexed", self.get_type())),
51			OP_ARRAY_INDEX => Err(anyhow!("Type {} cannot be indexed", self.get_type())),
52			_ => Err(anyhow!(
53				"Function {} cannot be called with arguments {:#?} on objects of type {}",
54				func,
55				args,
56				self.get_type()
57			)),
58		}
59	}
60
61	fn call(&self, func: &str, args: &[Box<dyn Value>]) -> anyhow::Result<Box<dyn Value>> {
62		self.call_base(func, args)
63	}
64
65	fn get_type(&self) -> Type;
66
67	fn as_any(&self) -> &dyn Any;
68
69	fn format(&self, buffer: &mut String, spec: FormatSpecifier);
70}
71
72#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
73pub(crate) enum FormatSpecifier {
74	Default,
75	Debug,
76	DebugAlt,
77}
78
79pub(crate) const OP_FIELD_ACCESS: &str = "!field";
80pub(crate) const OP_TUPLE_INDEX: &str = "!tuple_index";
81pub(crate) const OP_ARRAY_INDEX: &str = "!array_index";
82
83fn as_field_name(args: &[Box<dyn Value>]) -> &str {
84	assert!(
85		args.len() == 1,
86		"Accessing a field must have exactly one operand (the field name)"
87	);
88
89	args[0]
90		.as_any()
91		.downcast_ref::<String>()
92		.expect("The field name must be a string when accessing a field.")
93}
94
95fn as_index(args: &[Box<dyn Value>]) -> usize {
96	assert!(
97		args.len() == 1,
98		"Accessing a field must have exactly one operand (the field name)"
99	);
100
101	args[0]
102		.as_any()
103		.downcast_ref::<BigInt>()
104		.expect("The array index must be an integer.")
105		.to_usize()
106		.expect("The array index does not fit into the type usize.")
107}
108
109fn as_arguments_0(args: &[Box<dyn Value>]) -> anyhow::Result<()> {
110	if args.is_empty() {
111		Ok(())
112	} else {
113		Err(anyhow!("Wrong number of arguments (should be 0)"))
114	}
115}
116
117fn as_simple_arguments_1<T1: 'static>(args: &[Box<dyn Value>]) -> anyhow::Result<(&T1,)> {
118	if args.len() != 1 {
119		return Err(anyhow!("Wrong number of arguments (should be 1)"));
120	}
121
122	Ok((args[0]
123		.as_any()
124		.downcast_ref::<T1>()
125		.ok_or_else(|| anyhow!("Argument #1 should have type {}", type_name::<T1>()))?,))
126}
127
128fn as_named_arguments_1<T1: 'static>(args: &[(Option<String>, Box<dyn Value>)]) -> anyhow::Result<(&T1,)> {
129	if args.len() != 1 {
130		return Err(anyhow!("Wrong number of arguments (should be 1)"));
131	}
132
133	if args[0].0.is_some() {
134		return Err(anyhow!(
135			"Expected a single positional argument, found a named argument instead"
136		));
137	}
138
139	Ok((args[0]
140		.1
141		.as_any()
142		.downcast_ref::<T1>()
143		.ok_or_else(|| anyhow!("Argument #1 should have type {}", type_name::<T1>()))?,))
144}