nifty_codegen/compile/body/
download.rs1use std::mem::{offset_of, size_of};
4
5use cranelift_codegen::ir::types::{I8, I32};
6use cranelift_codegen::ir::{InstBuilder, MemFlags, Value};
7use cranelift_module::Module;
8use nifty_check::hir::{Download, DownloadCommand, Expr, PlaceStep, Type};
9use nifty_rt::{DownloadBinding, DownloadDesc};
10use nifty_syntax::Span;
11
12use super::{Body, Result, offset};
13
14impl<M: Module> Body<'_, '_, '_, M> {
15 pub(super) fn download(&mut self, download: &Download, span: Span) -> Result<()> {
19 let settings = [
20 &download.folder,
21 &download.name,
22 &download.connections,
23 &download.headers,
24 &download.retries,
25 ];
26 let indexes = download
27 .bindings
28 .iter()
29 .flat_map(|(_, place)| &place.path)
30 .filter_map(|step| match step {
31 PlaceStep::Index(index) => Some(index),
32 PlaceStep::Field(_) => None,
33 });
34 let after = |setting: usize| settings[setting..].iter().copied().chain(indexes.clone());
35 let url = self.expr(&download.url)?;
36 let url = self.hold_across(url, &Type::String, after(0))?;
37 let folder = self.expr(&download.folder)?;
38 let folder = self.hold_across(folder, &Type::String, after(1))?;
39 let name = self.expr(&download.name)?;
40 let name = self.hold_across(name, &Type::String, after(2))?;
41 let connections = self.int(&download.connections)?;
42 let headers = self.expr(&download.headers)?;
43 let headers = self.hold_across(headers, &download.headers.ty, after(4))?;
44 let retries = self.int(&download.retries)?;
45 let mut places = Vec::with_capacity(download.bindings.len());
46 for (field, place) in &download.bindings {
47 let path = self.path(place)?;
48 let Some(desc) = self.place_desc(&path)? else {
49 return self.fail_now(self.shared.runtime.fail_download_into_variable, span);
50 };
51 places.push((field.code(), desc));
52 }
53 let bindings = self.download_bindings(&places)?;
54 let desc = self.stack(size_of::<DownloadDesc>())?;
55 let len = self.usize(places.len())?;
56 for (value, at) in [
57 (url.value, offset_of!(DownloadDesc, url)),
58 (folder.value, offset_of!(DownloadDesc, folder)),
59 (name.value, offset_of!(DownloadDesc, name)),
60 (connections, offset_of!(DownloadDesc, connections)),
61 (headers.value, offset_of!(DownloadDesc, headers)),
62 (retries, offset_of!(DownloadDesc, retries)),
63 (bindings, offset_of!(DownloadDesc, bindings)),
64 (len, offset_of!(DownloadDesc, len)),
65 ] {
66 let at = offset(at)?;
67 self.b.ins().store(MemFlags::trusted(), value, desc, at);
68 }
69 let span = self.span(span)?;
70 let start = self.shared.runtime.download;
71 self.call_checked(start, &[self.context, desc, span]);
72 self.discard(url, &Type::String)?;
73 self.discard(folder, &Type::String)?;
74 self.discard(name, &Type::String)?;
75 self.discard(headers, &download.headers.ty)
76 }
77
78 fn download_bindings(&mut self, places: &[(u8, Value)]) -> Result<Value> {
81 let size = size_of::<DownloadBinding>();
82 let array = self.stack(places.len().max(1) * size)?;
83 for (index, &(field, place)) in places.iter().enumerate() {
84 let field = self.b.ins().iconst(I8, i64::from(field));
85 let field_at = offset(index * size + offset_of!(DownloadBinding, field))?;
86 let place_at = offset(index * size + offset_of!(DownloadBinding, place))?;
87 self.b
88 .ins()
89 .store(MemFlags::trusted(), field, array, field_at);
90 self.b
91 .ins()
92 .store(MemFlags::trusted(), place, array, place_at);
93 }
94 Ok(array)
95 }
96
97 pub(super) fn download_command(&mut self, command: DownloadCommand, id: &Expr) -> Result<()> {
99 let id_operand = self.expr(id)?;
100 let command = self.b.ins().iconst(I32, i64::from(command as u32));
101 let ask = self.shared.runtime.download_command;
102 self.call(ask, &[self.context, command, id_operand.value]);
103 self.discard(id_operand, &Type::String)
104 }
105
106 pub(super) fn format_bytes(&mut self, bytes: &Expr) -> Result<Value> {
108 let bytes = self.int(bytes)?;
109 let format = self.shared.runtime.format_bytes;
110 Ok(self.call1(format, &[bytes]))
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn a_bindings_field_is_stored_as_one_byte() {
120 assert_eq!(size_of::<nifty_check::hir::DownloadField>(), 1);
121 }
122}