uni_core/primitives/
now.rs1use crate::compat::Rc;
4use crate::interpreter::Interpreter;
5use crate::value::{RuntimeError, Value};
6
7#[cfg(not(target_os = "none"))]
8use std::cell::RefCell;
9#[cfg(target_os = "none")]
10use core::cell::RefCell;
11
12#[cfg(target_os = "none")]
14use crate::compat::ToString;
15
16#[cfg(target_os = "none")]
17use alloc::vec;
18
19pub fn now_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
23 let time_source = interp.time_source.as_ref().ok_or_else(|| {
25 RuntimeError::TypeError(
26 "now: no time source available - platform must inject TimeSource".to_string(),
27 )
28 })?;
29
30 let components = time_source.now();
32
33 let date_type_key = interp.intern_atom("<record-type:date>");
36 let date_entry = interp.dictionary.get(&date_type_key).ok_or_else(|| {
37 RuntimeError::TypeError(
38 "now: date record type not found - prelude not loaded?".to_string(),
39 )
40 })?;
41
42 match &date_entry.value {
44 Value::RecordType { .. } => {},
45 _ => {
46 return Err(RuntimeError::TypeError(
47 "now: 'date' is not a record type".to_string(),
48 ))
49 }
50 }
51
52 let field_values = vec![
54 Value::Int32(components.year),
55 Value::Int32(components.month as i32),
56 Value::Int32(components.day as i32),
57 Value::Int32(components.hour as i32),
58 Value::Int32(components.minute as i32),
59 Value::Int32(components.second as i32),
60 Value::Int32(components.offset_minutes),
61 ];
62
63 let date_type_name = interp.intern_atom("date");
66 let record = Value::Record {
67 type_name: date_type_name,
68 fields: Rc::new(RefCell::new(field_values)),
69 };
70
71 interp.push(record);
72 Ok(())
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::evaluator::execute_string;
79
80 #[test]
81 #[cfg(feature = "std")]
82 fn test_now_with_time_source() {
83 use crate::builtins::register_builtins;
84 use crate::hardware::linux_time::LinuxTimeSource;
85
86 let mut interp = Interpreter::new();
87 register_builtins(&mut interp);
88
89 interp.set_time_source(Box::new(LinuxTimeSource::new()));
91
92 execute_string(r#"
95 "year" "month" "day" "hour" "minute" "second" "offset" 7 list "date" make-record-type drop
96 "#, &mut interp).unwrap();
97
98 now_builtin(&mut interp).unwrap();
100
101 assert_eq!(interp.stack.len(), 1);
103
104 let value = interp.pop().unwrap();
105 match value {
106 Value::Record { type_name, fields } => {
107 assert_eq!(&*type_name, "date");
108 assert_eq!(fields.borrow().len(), 7);
109 }
110 _ => panic!("Expected record, got {:?}", value),
111 }
112 }
113
114 #[test]
115 fn test_now_without_time_source() {
116 let mut interp = Interpreter::new();
117
118 let result = now_builtin(&mut interp);
120 assert!(matches!(result, Err(RuntimeError::TypeError(_))));
121 }
122}