• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mattwparas / steel / 18461079395

13 Oct 2025 09:20AM UTC coverage: 42.731% (-0.9%) from 43.668%
18461079395

Pull #536

github

web-flow
Merge 6f55a8b56 into e378cba22
Pull Request #536: Initial proposal for no_std support

63 of 755 new or added lines in 38 files covered. (8.34%)

73 existing lines in 15 files now uncovered.

12324 of 28841 relevant lines covered (42.73%)

3215759.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/crates/steel-gen/src/permutations.rs
1
use alloc::{string::String, vec, vec::Vec};
2

3
use codegen::Impl;
4

5
// Awful, ugly back to generate all of the inputs that I need across different params
6

7
// It might be worth flattening this vector, but that is quite a bit of contiguous memory to allocate.
8
// lets just deal with the fact that this might be broken up and take the cache hits. Alternatively, it would probably
9
// make a lot of sense to do this with an iterator.
10

11
pub const SUPPORTED_FUNCTION_ARITY: u32 = 5;
12

UNCOV
13
fn generate_permutations<T: Copy>(input: &[T]) -> Vec<Vec<Vec<T>>> {
×
UNCOV
14
    let mut buffers = Vec::with_capacity(SUPPORTED_FUNCTION_ARITY as usize);
×
15

UNCOV
16
    for i in 0..SUPPORTED_FUNCTION_ARITY {
×
17
        buffers.push(Vec::with_capacity(input.len().pow(i)));
×
18
    }
19

UNCOV
20
    for a in input {
×
21
        buffers[0].push(vec![*a]);
×
22

UNCOV
23
        for b in input {
×
24
            buffers[1].push(vec![*a, *b]);
×
25

UNCOV
26
            for c in input {
×
27
                buffers[2].push(vec![*a, *b, *c]);
×
28

UNCOV
29
                for d in input {
×
30
                    buffers[3].push(vec![*a, *b, *c, *d]);
×
31

UNCOV
32
                    for e in input {
×
33
                        buffers[4].push(vec![*a, *b, *c, *d, *e]);
×
34

35
                        //     // for f in input {
36
                        //     //     buffers[5].push(vec![*a, *b, *c, *d, *e, *f]);
37

38
                        //     //     // TODO: If this can be done, we want to get up to like 8 parameters if possible?
39

40
                        //     //     // for g in input {
41
                        //     //     //     buffers[6].push(vec![*a, *b, *c, *d, *e, *f, *g]);
42

43
                        //     //     //     for h in input {
44
                        //     //     //         buffers[7].push(vec![*a, *b, *c, *d, *e, *f, *g, *h])
45
                        //     //     //     }
46
                        //     //     // }
47
                        // }
48
                    }
49
                }
50
            }
51
        }
52
    }
53

UNCOV
54
    buffers
×
55
}
56

57
#[derive(Copy, Clone)]
58
enum ValueKind {
59
    Value,
60
    Reference,
61
    MutReference,
62
}
63

64
impl ValueKind {
65
    fn format_array_to_tuple(values: &[ValueKind]) -> String {
66
        let mut output = "(".to_string();
67

68
        for i in 0..values.len() {
69
            output.push('T');
70
            output.push_str(&i.to_string());
71
            output.push(',');
72
        }
73

74
        output.push(')');
75

76
        output
77
    }
78

79
    // Fn(&SELF, AREA, &CTX)
80
    fn format_array_to_function_args(values: &[ValueKind]) -> String {
81
        let mut output = "(".to_string();
82

83
        for (i, value) in values.iter().enumerate() {
84
            if let Some(reference_modifier) = value.as_reference_type_repr() {
85
                output.push_str(reference_modifier);
86
                output.push(' ');
87
            }
88
            output.push('T');
89
            output.push_str(&i.to_string());
90
            output.push(',');
91
        }
92

93
        output.push(')');
94

95
        output
96
    }
97

98
    // Convert this to a reference type for the use of code gen
99
    fn as_reference_type_repr(&self) -> Option<&'static str> {
100
        match self {
101
            Self::Value => None,
102
            Self::Reference => Some("&"),
103
            Self::MutReference => Some("&mut"),
104
        }
105
    }
106

107
    // In theory, we might have more, but I need to iron this out from the
108
    // actual implementation side of things.
109
    fn as_from_trait_name(&self) -> &'static str {
110
        match self {
111
            Self::Value => "FromSteelVal",
112
            Self::Reference => "AsRefSteelVal",
113
            Self::MutReference => "AsRefMutSteelVal",
114
        }
115
    }
116
}
117

118
const FN: &str = "FN";
119
const RET: &str = "RET";
120

121
fn code_gen_permutation(values: &[ValueKind], id: usize, row: usize) -> String {
122
    // RegisterFn<FN, MarkerWrapper8<(SELF, AREA, CTX)>, RET>
123
    let mut trait_to_impl_type = codegen::Type::new("RegisterFn");
124
    trait_to_impl_type.generic(FN);
125
    let mut wrapper = codegen::Type::new(format!("Marker{row}{id}"));
126
    wrapper.generic(ValueKind::format_array_to_tuple(values));
127
    trait_to_impl_type.generic(wrapper);
128
    trait_to_impl_type.generic(RET);
129

130
    // Target type to impl the trait for
131
    // let mut impl_trait = Impl::new("BuiltInModule");
132

133
    let mut impl_trait = Impl::new("FakeEngine");
134

135
    // We're implementing the above RegisterFn trait
136
    impl_trait.impl_trait(trait_to_impl_type);
137

138
    let ret_type = codegen::Type::new(RET);
139

140
    impl_trait.generic(RET);
141
    impl_trait.bound(RET, "IntoSteelVal"); // TODO: Figure out if these bounds are respected or not
142
    for (i, value) in values.iter().enumerate() {
143
        let type_name = format!("T{i}");
144

145
        impl_trait.generic(&type_name);
146
        impl_trait.bound(&type_name, value.as_from_trait_name()); // TODO: This is where we're gonna need to match to pick the right kind
147
    }
148

149
    impl_trait.generic(FN);
150
    // impl_trait.bound()
151

152
    let function_string = "Fn".to_string()
153
        + &ValueKind::format_array_to_function_args(values)
154
        + " -> "
155
        + "RET + SendSyncStatic";
156

157
    impl_trait.bound(FN, &function_string);
158

159
    let function_def = impl_trait.new_fn("register_fn");
160

161
    // Function signature
162
    function_def
163
        .arg_mut_self()
164
        .arg("name", "&'static str")
165
        .arg("func", FN)
166
        .ret("&mut Self");
167

168
    function_def.line("let f = move |args: &[SteelVal]| -> Result<SteelVal> {");
169
    function_def.line(format!("if args.len() != {} {{", values.len()));
170
    function_def.line(format!(
171
        "stop!(ArityMismatch => \"{{}} expected {} arguments, got {{}}\", name, args.len());",
172
        values.len(),
173
    ));
174
    function_def.line("}");
175

176
    for (i, value) in values.iter().enumerate() {
177
        match value {
178
            ValueKind::Value => {
179
                function_def.line(format!(
180
                    "let mut v{i} = <T{i}>::from_steelval(&args[{i}])?;"
181
                ));
182
            }
183
            ValueKind::Reference => {
184
                function_def.line(format!(
185
                    "let mut nursery{i} = <T{i} as AsRefSteelVal>::Nursery::default();"
186
                ));
187
                function_def.line(format!(
188
                    "let mut v{i} = <T{i}>::as_ref(&args[{i}], &mut nursery{i})?;"
189
                ));
190
            }
191
            ValueKind::MutReference => {
192
                function_def.line(format!("let mut v{i} = <T{i}>::as_mut_ref(&args[{i}])?;"));
193
            }
194
        }
195
    }
196

197
    {
198
        function_def.line("let res = func(");
199

200
        for (i, value) in values.iter().enumerate() {
201
            // function_def.line
202

203
            let mut var = String::new();
204
            if let Some(modifier) = value.as_reference_type_repr() {
205
                var.push_str(modifier);
206
            }
207

208
            var.push_str(&format!(" v{i},"));
209

210
            function_def.line(var);
211
        }
212

213
        function_def.line(");");
214

215
        function_def.line("res.into_steelval()");
216
    }
217

218
    function_def.line("};");
219

220
    function_def.line(format!(
221
        r#"
222

223
        self.register_value(
224
            name,
225
            SteelVal::BoxedFunction(Rc::new(BoxedDynFunction::new(
226
                Arc::new(f), 
227
                Some(name), 
228
                Some({})
229
            ))),
230
        )
231
            
232
        "#,
233
        values.len()
234
    ));
235

236
    let mut scope = codegen::Scope::new();
237

238
    let mut marker = scope.new_struct(&format!("Marker{row}{id}"));
239

240
    marker.generic("ARGS");
241
    marker.tuple_field("PhantomData<ARGS>");
242

243
    scope.push_impl(impl_trait);
244

245
    scope.to_string()
246
}
247

248
pub fn code_gen() -> String {
249
    let values = &[
250
        ValueKind::Value,
251
        ValueKind::Reference,
252
        ValueKind::MutReference,
253
    ];
254

255
    let permutations = generate_permutations(values);
256

257
    let mut out = Vec::new();
258

259
    for (r, row) in permutations.into_iter().enumerate() {
260
        for (index, column) in row.into_iter().enumerate() {
261
            out.push(code_gen_permutation(&column, index, r));
262
        }
263
    }
264

265
    out.join("\n")
266
}
267

268
#[test]
269
fn simple_code_gen() {
270
    let values = &[
271
        ValueKind::Value,
272
        ValueKind::Reference,
273
        ValueKind::MutReference,
274
    ];
275

276
    // println!("{}", code_gen_permutation(values));
277

278
    let permutations = generate_permutations(values);
279

280
    for (r, row) in permutations.into_iter().enumerate() {
281
        for (index, column) in row.into_iter().enumerate() {
282
            println!("{}", code_gen_permutation(&column, index, r));
283
        }
284
    }
285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc