1use std::cell::OnceCell;
21use std::rc::Rc;
22
23#[derive(Clone)]
31pub struct Lazy<T: Clone> {
32 inner: Rc<LazyInner<T>>,
33}
34
35struct LazyInner<T: Clone> {
36 cache: OnceCell<T>,
38 compute: std::cell::Cell<Option<Box<dyn FnOnce() -> T>>>,
40}
41
42impl<T: Clone> Lazy<T> {
43 pub fn defer(f: impl FnOnce() -> T + 'static) -> Self {
45 Self {
46 inner: Rc::new(LazyInner {
47 cache: OnceCell::new(),
48 compute: std::cell::Cell::new(Some(Box::new(f))),
49 }),
50 }
51 }
52
53 pub fn ready(value: T) -> Self {
55 let cache = OnceCell::new();
56 let _ = cache.set(value);
57 Self {
58 inner: Rc::new(LazyInner {
59 cache,
60 compute: std::cell::Cell::new(None),
61 }),
62 }
63 }
64
65 pub fn demand(&self) -> &T {
67 self.inner.cache.get_or_init(|| {
68 let compute = self.inner.compute.take()
69 .expect("Lazy: cache empty but compute already consumed (bug)");
70 compute()
71 })
72 }
73
74 pub fn is_ready(&self) -> bool {
76 self.inner.cache.get().is_some()
77 }
78}
79
80impl<T: Clone + std::fmt::Debug> std::fmt::Debug for Lazy<T> {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 if let Some(v) = self.inner.cache.get() {
83 write!(f, "Lazy({v:?})")
84 } else {
85 write!(f, "Lazy(<deferred>)")
86 }
87 }
88}
89
90#[derive(Clone)]
99pub struct FallibleLazy<T: Clone, E: Clone> {
100 inner: Rc<FallibleLazyInner<T, E>>,
101}
102
103struct FallibleLazyInner<T: Clone, E: Clone> {
104 cache: OnceCell<T>,
105 compute: std::cell::Cell<Option<Box<dyn FnOnce() -> Result<T, E>>>>,
106}
107
108impl<T: Clone, E: Clone> FallibleLazy<T, E> {
109 pub fn defer(f: impl FnOnce() -> Result<T, E> + 'static) -> Self {
111 Self {
112 inner: Rc::new(FallibleLazyInner {
113 cache: OnceCell::new(),
114 compute: std::cell::Cell::new(Some(Box::new(f))),
115 }),
116 }
117 }
118
119 pub fn ready(value: T) -> Self {
121 let cache = OnceCell::new();
122 let _ = cache.set(value);
123 Self {
124 inner: Rc::new(FallibleLazyInner {
125 cache,
126 compute: std::cell::Cell::new(None),
127 }),
128 }
129 }
130
131 pub fn demand(&self) -> Result<&T, E> {
135 if let Some(v) = self.inner.cache.get() {
136 return Ok(v);
137 }
138 if let Some(compute) = self.inner.compute.take() {
139 match compute() {
140 Ok(val) => {
141 let _ = self.inner.cache.set(val);
142 Ok(self.inner.cache.get().unwrap())
143 }
144 Err(e) => Err(e),
145 }
146 } else {
147 panic!("FallibleLazy: cache empty and compute consumed without storing result")
150 }
151 }
152
153 pub fn is_ready(&self) -> bool {
155 self.inner.cache.get().is_some()
156 }
157}
158
159impl<T: Clone + std::fmt::Debug, E: Clone> std::fmt::Debug for FallibleLazy<T, E> {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 if let Some(v) = self.inner.cache.get() {
162 write!(f, "FallibleLazy({v:?})")
163 } else {
164 write!(f, "FallibleLazy(<deferred>)")
165 }
166 }
167}
168
169use crate::value::{Value, EvalError, NixAttrs, intern, resolve};
172use sui_intern::Symbol;
173
174pub type LazyValue = FallibleLazy<Value, EvalError>;
180
181#[derive(Clone, Debug)]
192pub struct LazyAttrs {
193 entries: im_rc::HashMap<Symbol, LazyValue, rustc_hash::FxBuildHasher>,
194}
195
196impl LazyAttrs {
197 pub fn new() -> Self {
199 Self {
200 entries: im_rc::HashMap::default(),
201 }
202 }
203
204 pub fn insert(&mut self, key: Symbol, value: LazyValue) {
206 self.entries.insert(key, value);
207 }
208
209 pub fn insert_ready(&mut self, key: Symbol, value: Value) {
211 self.entries.insert(key, LazyValue::ready(value));
212 }
213
214 pub fn insert_deferred<F>(&mut self, key: Symbol, f: F)
216 where
217 F: FnOnce() -> Result<Value, EvalError> + 'static,
218 {
219 self.entries.insert(key, LazyValue::defer(f));
220 }
221
222 pub fn get(&self, key: &str) -> Option<Result<&Value, EvalError>> {
224 let sym = intern(key);
225 self.entries.get(&sym).map(|lv| lv.demand())
226 }
227
228 pub fn get_sym(&self, sym: &Symbol) -> Option<Result<&Value, EvalError>> {
230 self.entries.get(sym).map(|lv| lv.demand())
231 }
232
233 pub fn contains_key(&self, key: &str) -> bool {
235 self.entries.contains_key(&intern(key))
236 }
237
238 pub fn keys(&self) -> impl Iterator<Item = String> + '_ {
240 self.entries.keys().map(|s| resolve(*s))
241 }
242
243 pub fn len(&self) -> usize {
245 self.entries.len()
246 }
247
248 pub fn is_empty(&self) -> bool {
250 self.entries.is_empty()
251 }
252
253 pub fn update(&self, other: &LazyAttrs) -> LazyAttrs {
256 let mut result = self.entries.clone();
257 for (k, v) in other.entries.iter() {
258 result.insert(*k, v.clone());
259 }
260 LazyAttrs { entries: result }
261 }
262
263 pub fn force_all(&self) -> Result<NixAttrs, EvalError> {
266 let mut attrs = NixAttrs::new();
267 for (sym, lv) in self.entries.iter() {
268 let val = lv.demand()?;
269 attrs.insert(resolve(*sym), val.clone());
270 }
271 Ok(attrs)
272 }
273}
274
275impl Default for LazyAttrs {
276 fn default() -> Self {
277 Self::new()
278 }
279}
280
281#[derive(Clone, Debug)]
290pub enum OverlayAttrs {
291 Base(Rc<NixAttrs>),
293 Overlay {
296 left: Rc<OverlayAttrs>,
297 right: Rc<NixAttrs>,
298 },
299}
300
301impl OverlayAttrs {
302 pub fn base(attrs: NixAttrs) -> Self {
304 OverlayAttrs::Base(Rc::new(attrs))
305 }
306
307 pub fn overlay(self, right: NixAttrs) -> Self {
310 OverlayAttrs::Overlay {
311 left: Rc::new(self),
312 right: Rc::new(right),
313 }
314 }
315
316 pub fn get(&self, key: &str) -> Option<&Value> {
320 match self {
321 OverlayAttrs::Base(attrs) => attrs.get(key),
322 OverlayAttrs::Overlay { left, right } => {
323 right.get(key).or_else(|| left.get(key))
325 }
326 }
327 }
328
329 pub fn get_sym(&self, sym: &Symbol) -> Option<&Value> {
331 match self {
332 OverlayAttrs::Base(attrs) => attrs.get_sym(sym),
333 OverlayAttrs::Overlay { left, right } => {
334 right.get_sym(sym).or_else(|| left.get_sym(sym))
335 }
336 }
337 }
338
339 pub fn contains_key(&self, key: &str) -> bool {
341 match self {
342 OverlayAttrs::Base(attrs) => attrs.contains_key(key),
343 OverlayAttrs::Overlay { left, right } => {
344 right.contains_key(key) || left.contains_key(key)
345 }
346 }
347 }
348
349 pub fn all_keys(&self) -> Vec<String> {
352 let mut seen = std::collections::HashSet::new();
353 let mut result = Vec::new();
354 self.collect_keys(&mut seen, &mut result);
355 result.sort();
356 result
357 }
358
359 fn collect_keys(&self, seen: &mut std::collections::HashSet<String>, result: &mut Vec<String>) {
360 match self {
361 OverlayAttrs::Base(attrs) => {
362 for (k, _) in attrs.iter_unsorted() {
363 if seen.insert(k.clone()) {
364 result.push(k);
365 }
366 }
367 }
368 OverlayAttrs::Overlay { left, right } => {
369 for (k, _) in right.iter_unsorted() {
371 if seen.insert(k.clone()) {
372 result.push(k);
373 }
374 }
375 left.collect_keys(seen, result);
376 }
377 }
378 }
379
380 pub fn flatten(&self) -> NixAttrs {
382 match self {
383 OverlayAttrs::Base(attrs) => (**attrs).clone(),
384 OverlayAttrs::Overlay { left, right } => {
385 let base = left.flatten();
386 base.update(right)
387 }
388 }
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 use super::*;
395 use std::cell::Cell;
396
397 #[test]
400 fn deferred_not_evaluated_until_demand() {
401 let evaluated = Rc::new(Cell::new(false));
402 let e = evaluated.clone();
403 let lazy = Lazy::defer(move || {
404 e.set(true);
405 42
406 });
407 assert!(!evaluated.get());
408 assert_eq!(*lazy.demand(), 42);
409 assert!(evaluated.get());
410 }
411
412 #[test]
413 fn demand_memoizes() {
414 let count = Rc::new(Cell::new(0));
415 let c = count.clone();
416 let lazy = Lazy::defer(move || {
417 c.set(c.get() + 1);
418 "hello"
419 });
420 assert_eq!(*lazy.demand(), "hello");
421 assert_eq!(*lazy.demand(), "hello");
422 assert_eq!(count.get(), 1); }
424
425 #[test]
426 fn ready_is_immediate() {
427 let lazy = Lazy::ready(99);
428 assert!(lazy.is_ready());
429 assert_eq!(*lazy.demand(), 99);
430 }
431
432 #[test]
433 fn clone_shares_computation() {
434 let count = Rc::new(Cell::new(0));
435 let c = count.clone();
436 let lazy = Lazy::defer(move || {
437 c.set(c.get() + 1);
438 7
439 });
440 let clone = lazy.clone();
441 assert_eq!(*lazy.demand(), 7);
442 assert_eq!(*clone.demand(), 7); assert_eq!(count.get(), 1); }
445
446 #[test]
449 fn fallible_lazy_success() {
450 let fl: FallibleLazy<i64, String> = FallibleLazy::defer(|| Ok(42));
451 assert!(!fl.is_ready());
452 assert_eq!(*fl.demand().unwrap(), 42);
453 assert!(fl.is_ready());
454 assert_eq!(*fl.demand().unwrap(), 42); }
456
457 #[test]
458 fn fallible_lazy_ready() {
459 let fl: FallibleLazy<i64, String> = FallibleLazy::ready(99);
460 assert!(fl.is_ready());
461 assert_eq!(*fl.demand().unwrap(), 99);
462 }
463
464 #[test]
465 fn fallible_lazy_clone_shares() {
466 let count = Rc::new(Cell::new(0));
467 let c = count.clone();
468 let fl: FallibleLazy<i64, String> = FallibleLazy::defer(move || {
469 c.set(c.get() + 1);
470 Ok(7)
471 });
472 let clone = fl.clone();
473 assert_eq!(*fl.demand().unwrap(), 7);
474 assert_eq!(*clone.demand().unwrap(), 7);
475 assert_eq!(count.get(), 1); }
477
478 #[test]
481 fn lazy_attrs_keys_without_forcing() {
482 let evaluated = Rc::new(Cell::new(false));
483 let e = evaluated.clone();
484 let mut attrs = LazyAttrs::new();
485 attrs.insert_deferred(intern("expensive"), move || {
486 e.set(true);
487 Ok(Value::Int(42))
488 });
489 attrs.insert_ready(intern("cheap"), Value::Int(1));
490
491 assert_eq!(attrs.len(), 2);
493 assert!(attrs.contains_key("expensive"));
494 assert!(attrs.contains_key("cheap"));
495 assert!(!evaluated.get()); let val = attrs.get("expensive").unwrap().unwrap();
499 assert_eq!(*val, Value::Int(42));
500 assert!(evaluated.get()); }
502
503 #[test]
504 fn lazy_attrs_update_no_forcing() {
505 let evaluated = Rc::new(Cell::new(false));
506 let e = evaluated.clone();
507 let mut a = LazyAttrs::new();
508 a.insert_ready(intern("x"), Value::Int(1));
509 let mut b = LazyAttrs::new();
510 b.insert_deferred(intern("y"), move || {
511 e.set(true);
512 Ok(Value::Int(2))
513 });
514
515 let merged = a.update(&b);
517 assert_eq!(merged.len(), 2);
518 assert!(!evaluated.get()); assert_eq!(*merged.get("x").unwrap().unwrap(), Value::Int(1));
522 assert!(!evaluated.get()); }
524
525 #[test]
526 fn lazy_attrs_force_all() {
527 let mut attrs = LazyAttrs::new();
528 attrs.insert_ready(intern("a"), Value::Int(1));
529 attrs.insert_deferred(intern("b"), || Ok(Value::Int(2)));
530 let nix_attrs = attrs.force_all().unwrap();
531 assert_eq!(nix_attrs.get("a"), Some(&Value::Int(1)));
532 assert_eq!(nix_attrs.get("b"), Some(&Value::Int(2)));
533 }
534
535 #[test]
538 fn overlay_get_right_overrides_left() {
539 let mut left = NixAttrs::new();
540 left.insert("x".to_string(), Value::Int(1));
541 left.insert("y".to_string(), Value::Int(2));
542
543 let mut right = NixAttrs::new();
544 right.insert("x".to_string(), Value::Int(10)); let overlay = OverlayAttrs::base(left).overlay(right);
547 assert_eq!(overlay.get("x"), Some(&Value::Int(10))); assert_eq!(overlay.get("y"), Some(&Value::Int(2))); assert_eq!(overlay.get("z"), None); }
551
552 #[test]
553 fn overlay_chain_three_levels() {
554 let mut a = NixAttrs::new();
555 a.insert("x".to_string(), Value::Int(1));
556 let mut b = NixAttrs::new();
557 b.insert("y".to_string(), Value::Int(2));
558 let mut c = NixAttrs::new();
559 c.insert("x".to_string(), Value::Int(3)); let chain = OverlayAttrs::base(a).overlay(b).overlay(c);
562 assert_eq!(chain.get("x"), Some(&Value::Int(3))); assert_eq!(chain.get("y"), Some(&Value::Int(2))); }
565
566 #[test]
567 fn overlay_is_o1_construction() {
568 let mut big = NixAttrs::new();
571 for i in 0..1000 {
572 big.insert(format!("attr_{i}"), Value::Int(i));
573 }
574 let mut small = NixAttrs::new();
575 small.insert("target".to_string(), Value::Int(42));
576
577 let overlay = OverlayAttrs::base(big).overlay(small);
579 assert_eq!(overlay.get("target"), Some(&Value::Int(42)));
580 assert_eq!(overlay.get("attr_0"), Some(&Value::Int(0)));
581 }
582
583 #[test]
584 fn overlay_all_keys() {
585 let mut a = NixAttrs::new();
586 a.insert("x".to_string(), Value::Int(1));
587 a.insert("y".to_string(), Value::Int(2));
588 let mut b = NixAttrs::new();
589 b.insert("y".to_string(), Value::Int(20));
590 b.insert("z".to_string(), Value::Int(30));
591
592 let overlay = OverlayAttrs::base(a).overlay(b);
593 let keys = overlay.all_keys();
594 assert_eq!(keys, vec!["x", "y", "z"]); }
596
597 #[test]
598 fn overlay_contains_key() {
599 let mut a = NixAttrs::new();
600 a.insert("x".to_string(), Value::Int(1));
601 let overlay = OverlayAttrs::base(a);
602 assert!(overlay.contains_key("x"));
603 assert!(!overlay.contains_key("y"));
604 }
605
606 #[test]
607 fn overlay_flatten() {
608 let mut a = NixAttrs::new();
609 a.insert("x".to_string(), Value::Int(1));
610 let mut b = NixAttrs::new();
611 b.insert("x".to_string(), Value::Int(2));
612 b.insert("y".to_string(), Value::Int(3));
613
614 let overlay = OverlayAttrs::base(a).overlay(b);
615 let flat = overlay.flatten();
616 assert_eq!(flat.get("x"), Some(&Value::Int(2)));
617 assert_eq!(flat.get("y"), Some(&Value::Int(3)));
618 }
619}