1use super::{CoercionKind, Value};
7use crate::errors::ErrorKind;
8use crate::generators::{self, GenCo};
9use crate::NixContext;
10
11use bstr::ByteSlice;
12use serde_json::value::to_value;
13use serde_json::Value as Json; use serde_json::{Map, Number};
15
16impl Value {
17 pub async fn into_contextful_json(self, co: &GenCo) -> Result<(Json, NixContext), ErrorKind> {
21 let self_forced = generators::request_force(co, self).await;
22 let mut context = NixContext::new();
23
24 let value = match self_forced {
25 Value::Null => Json::Null,
26 Value::Bool(b) => Json::Bool(b),
27 Value::Integer(i) => Json::Number(Number::from(i)),
28 Value::Float(f) => to_value(f)?,
29 Value::String(s) => {
30 context.mimic(&s);
31
32 Json::String(s.to_str()?.to_owned())
33 }
34
35 Value::Path(p) => {
36 let imported = generators::request_path_import(co, *p).await;
37 let path = imported.to_string_lossy().to_string();
38 context = context.append(crate::NixContextElement::Plain(path.clone()));
39 Json::String(path)
40 }
41
42 Value::List(l) => {
43 let mut out = Vec::with_capacity(l.len());
44
45 for val in l.into_iter() {
46 let (json_item, ctx) = Box::pin(val.into_contextful_json(co)).await?;
47 context.extend(ctx.into_iter());
48 out.push(json_item);
49 }
50
51 Json::Array(out)
52 }
53
54 Value::Attrs(attrs) => {
55 if attrs.select("__toString").is_some() {
59 let span = generators::request_span(co).await;
60 match Value::Attrs(attrs)
61 .coerce_to_string_(
62 co,
63 CoercionKind {
64 strong: false,
65 import_paths: false,
66 },
67 span,
68 )
69 .await?
70 {
71 Value::Catchable(cek) => return Err(ErrorKind::CatchableError(*cek)),
72 Value::String(s) => {
73 let mut fresh = NixContext::new();
76 fresh.mimic(&s);
77 return Ok((Json::String(s.to_str()?.to_owned()), fresh));
78 }
79 _ => panic!("Value::coerce_to_string_() returned a non-string!"),
80 }
81 }
82
83 if let Some(out_path) = attrs.select("outPath") {
87 let (json_out_path, ctx) =
88 Box::pin(out_path.clone().into_contextful_json(co)).await?;
89 context.extend(ctx.into_iter());
90 return Ok((json_out_path, context));
91 }
92
93 let mut out = Map::with_capacity(attrs.len());
94 for (name, value) in attrs.into_iter_sorted() {
95 let (json_value, ctx) = Box::pin(value.into_contextful_json(co)).await?;
96 context.extend(ctx.into_iter());
97 out.insert(name.to_str()?.to_owned(), json_value);
98 }
99
100 Json::Object(out)
101 }
102
103 Value::Catchable(c) => return Err(ErrorKind::CatchableError(*c)),
104
105 val @ Value::Closure(_)
106 | val @ Value::Thunk(_)
107 | val @ Value::Builtin(_)
108 | val @ Value::AttrNotFound
109 | val @ Value::Blueprint(_)
110 | val @ Value::DeferredUpvalue(_)
111 | val @ Value::UnresolvedPath(_)
112 | val @ Value::FinaliseRequest(_) => {
113 return Err(ErrorKind::NotSerialisableToJson(val.type_of()))
114 }
115 };
116 Ok((value, context))
117 }
118}