build_info_proc/format/value/
mod.rs1use 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}