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

mattwparas / steel / 11947392359

21 Nov 2024 05:44AM UTC coverage: 46.072% (-0.2%) from 46.234%
11947392359

Pull #291

github

web-flow
Merge 8d943de47 into 9a2bb2ef5
Pull Request #291: Add rustls library and fix free identifier error message

16 of 86 new or added lines in 6 files covered. (18.6%)

37 existing lines in 10 files now uncovered.

12334 of 26771 relevant lines covered (46.07%)

415077.16 hits per line

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

58.24
/crates/steel-core/src/values/functions.rs
1
#![allow(unused)]
2

3
use std::{
4
    cell::{Cell, RefCell},
5
    collections::HashMap,
6
    convert::TryFrom,
7
    hash::Hasher,
8
    sync::Arc,
9
};
10

11
use fxhash::FxHashSet;
12

13
use crate::{
14
    core::{instructions::DenseInstruction, opcode::OpCode},
15
    gc::{
16
        shared::{MutContainer, ShareableMut},
17
        Gc, Shared, SharedMut,
18
    },
19
    parser::{parser::SyntaxObjectId, span::Span},
20
    rvals::{
21
        from_serializable_value, into_serializable_value, AsRefSteelVal, Custom, FunctionSignature,
22
        HeapSerializer, IntoSteelVal, MutFunctionSignature, SerializableSteelVal, SteelString,
23
    },
24
    steel_vm::{
25
        register_fn::SendSyncStatic,
26
        vm::{BlockMetadata, BlockPattern, BuiltInSignature},
27
    },
28
    // values::contracts::ContractedFunction,
29
    SteelErr,
30
    SteelVal,
31
};
32

33
use super::{
34
    closed::{Heap, HeapRef},
35
    structs::UserDefinedStruct,
36
};
37

38
// pub(crate) enum Function {
39
//     BoxedFunction(BoxedFunctionSignature),
40
//     Closure(Gc<ByteCodeLambda>),
41
//     FuncV(FunctionSignature),
42
//     ContractedFunction(Gc<ContractedFunction>),
43
//     MutFuncV(MutFunctionSignature),
44
//     Builtin(BuiltInSignature),
45
// }
46

47
// Keep track of this metadata table for getting the docs associated
48
// with a given function?
49
pub struct LambdaMetadataTable {
50
    fn_ptr_table: HashMap<usize, SteelString>,
51
}
52

53
impl Custom for LambdaMetadataTable {}
54

55
impl LambdaMetadataTable {
56
    pub fn new() -> Self {
4✔
57
        Self {
58
            fn_ptr_table: HashMap::new(),
4✔
59
        }
60
    }
61

62
    pub fn add(&mut self, function: SteelVal, doc: SteelString) {
392✔
63
        match function {
392✔
64
            SteelVal::Closure(b) => {
392✔
65
                self.fn_ptr_table.insert(b.id as _, doc);
392✔
66
            }
67
            SteelVal::BoxedFunction(b) => {
×
68
                self.fn_ptr_table.insert(Gc::as_ptr(&b) as usize, doc);
×
69
            }
70
            _ => {}
×
71
        }
72
    }
73

74
    pub fn get(&self, function: SteelVal) -> Option<SteelString> {
×
75
        match function {
×
76
            SteelVal::Closure(b) => self.fn_ptr_table.get(&(b.id as _)).cloned(),
×
77
            SteelVal::BoxedFunction(b) => {
×
78
                self.fn_ptr_table.get(&(Gc::as_ptr(&b) as usize)).cloned()
×
79
            }
80
            _ => None,
×
81
        }
82
    }
83

84
    // TODO: This will need to get called in other places
85
    pub fn collect_garbage(&mut self, keep_set: impl Iterator<Item = usize>) {
×
86
        let set = keep_set.collect::<std::collections::HashSet<_>>();
×
87

88
        self.fn_ptr_table.retain(|k, _| set.contains(k));
×
89
    }
90
}
91

92
#[derive(Clone, Debug)]
93
pub struct ByteCodeLambda {
94
    pub(crate) id: u32,
95
    /// body of the function with identifiers yet to be bound
96
    #[cfg(feature = "dynamic")]
97
    pub(crate) body_exp: RefCell<Shared<[DenseInstruction]>>,
98

99
    #[cfg(not(feature = "dynamic"))]
100
    pub(crate) body_exp: Shared<[DenseInstruction]>,
101

102
    pub(crate) arity: u16,
103

104
    #[cfg(feature = "dynamic")]
105
    call_count: Cell<usize>,
106

107
    pub(crate) is_multi_arity: bool,
108

109
    pub(crate) captures: Vec<SteelVal>,
110
    #[cfg(feature = "dynamic")]
111
    pub(crate) blocks: RefCell<Vec<(BlockPattern, BlockMetadata)>>,
112

113
    // This is a little suspicious, but it should give us the necessary information to attach a struct of metadata
114
    #[cfg(feature = "sync")]
115
    contract: SharedMut<Option<Gc<UserDefinedStruct>>>,
116

117
    #[cfg(not(feature = "sync"))]
118
    contract: MutContainer<Option<Gc<UserDefinedStruct>>>,
119
}
120

121
impl PartialEq for ByteCodeLambda {
UNCOV
122
    fn eq(&self, other: &Self) -> bool {
×
123
        // self.body_exp == other.body_exp &&
UNCOV
124
        self.arity == other.arity && self.id == other.id
×
125
    }
126
}
127

128
impl Eq for ByteCodeLambda {}
129

130
impl std::hash::Hash for ByteCodeLambda {
131
    fn hash<H: Hasher>(&self, state: &mut H) {
1,458✔
132
        self.id.hash(state);
1,458✔
133
        // self.body_exp.as_ptr().hash(state);
134
        self.arity.hash(state);
1,458✔
135

136
        // self.sub_expression_env.as_ptr().hash(state);
137
    }
138
}
139

140
// Can this be moved across threads? What does it cost to execute a closure in another thread?
141
// Engine instances be deep cloned?
142
pub struct SerializedLambda {
143
    pub id: u32,
144
    pub body_exp: Vec<DenseInstruction>,
145
    pub arity: usize,
146
    pub is_multi_arity: bool,
147
    // TODO: Go ahead and create a ThreadSafeSteelVal where we will just deep clone everything, move
148
    // it across the thread, and reconstruct on the other side.
149
    pub captures: Vec<SerializableSteelVal>,
150
}
151

152
#[derive(Clone)]
153
pub struct SerializedLambdaPrototype {
154
    pub id: u32,
155
    pub body_exp: Vec<DenseInstruction>,
156
    pub arity: usize,
157
    pub is_multi_arity: bool,
158
    // TODO: Go ahead and create a ThreadSafeSteelVal where we will just deep clone everything, move
159
    // it across the thread, and reconstruct on the other side.
160
    // pub captures: Vec<SerializableSteelVal>,
161
}
162

163
// TODO
164
// is_let can probably be localized to a specific kind of function
165
// is_multi_arity can also be localized to a specific kind of function
166
impl ByteCodeLambda {
167
    pub fn new(
28,421✔
168
        id: u32,
169
        body_exp: Shared<[DenseInstruction]>,
170
        arity: usize,
171
        is_multi_arity: bool,
172
        captures: Vec<SteelVal>,
173
        // heap_allocated: Vec<HeapRef<SteelVal>>,
174
    ) -> ByteCodeLambda {
175
        // debug_assert_eq!(body_exp.len(), spans.len());
176

177
        ByteCodeLambda {
178
            id,
179

180
            #[cfg(feature = "dynamic")]
181
            body_exp: RefCell::new(body_exp),
28,421✔
182
            #[cfg(not(feature = "dynamic"))]
183
            body_exp,
184

185
            arity: arity as u16,
28,421✔
186

187
            #[cfg(feature = "dynamic")]
188
            call_count: Cell::new(0),
28,421✔
189

190
            is_multi_arity,
191
            captures,
192

193
            #[cfg(feature = "sync")]
194
            contract: SharedMut::new(MutContainer::new(None)),
28,421✔
195

196
            #[cfg(not(feature = "sync"))]
197
            contract: MutContainer::new(None),
28,421✔
198

199
            #[cfg(feature = "dynamic")]
200
            blocks: RefCell::new(Vec::new()),
28,421✔
201
        }
202
    }
203

204
    pub(crate) fn from_serialized(heap: &mut HeapSerializer, value: SerializedLambda) -> Self {
×
205
        ByteCodeLambda::new(
206
            value.id,
×
207
            value.body_exp.into(),
×
208
            value.arity,
×
209
            value.is_multi_arity,
×
210
            value
×
211
                .captures
×
212
                .into_iter()
×
213
                .map(|x| from_serializable_value(heap, x))
×
214
                .collect(),
×
215
            // Vec::new(),
216
        )
217
    }
218

219
    pub fn main(instructions: Vec<DenseInstruction>) -> ByteCodeLambda {
5✔
220
        Self::new(
221
            SyntaxObjectId::fresh().into(),
5✔
222
            instructions.into(),
5✔
223
            0,
224
            false,
225
            Vec::default(),
5✔
226
            // Vec::default(),
227
            // Rc::from([]),
228
        )
229
    }
230

231
    // pub fn id(&self) -> usize {
232
    //     self.id
233
    // }
234

235
    pub fn set_captures(&mut self, captures: Vec<SteelVal>) {
284,812✔
236
        self.captures = captures;
284,812✔
237
    }
238

239
    // pub fn set_heap_allocated(&mut self, heap_allocated: Vec<HeapRef<SteelVal>>) {
240
    //     self.heap_allocated = RefCell::new(heap_allocated);
241
    // }
242

243
    pub fn body_exp(&self) -> Shared<[DenseInstruction]> {
13,232,501✔
244
        #[cfg(feature = "dynamic")]
245
        return Shared::clone(&self.body_exp.borrow());
13,232,501✔
246

247
        #[cfg(not(feature = "dynamic"))]
248
        Shared::clone(&self.body_exp)
13,232,501✔
249
    }
250

251
    pub fn body_mut_exp(&mut self) -> Shared<[DenseInstruction]> {
×
252
        #[cfg(feature = "dynamic")]
253
        return Shared::clone(self.body_exp.get_mut());
×
254

255
        #[cfg(not(feature = "dynamic"))]
256
        Shared::clone(&self.body_exp)
×
257
    }
258

259
    // pub fn spans(&self) -> Rc<[Span]> {
260
    //     Rc::clone(&self.spans)
261
    // }
262

263
    // Get the starting index in the instruction set, and the new ID to associate with this
264
    // super instruction set.
265
    // Deep copy the old instruction set, update the new spot to have a dynamic super instruction
266
    // associated with it.
267
    #[cfg(feature = "dynamic")]
268
    pub fn update_to_super_instruction(
269
        &self,
270
        start: usize,
271
        super_instruction_id: usize,
272
    ) -> (DenseInstruction, Shared<[DenseInstruction]>) {
273
        let mut guard = self.body_exp.borrow_mut();
274
        let mut old: Box<[_]> = guard.iter().copied().collect();
275

276
        // set up the head instruction to get returned, we'll need it in the block first
277
        let head_instruction = old[start];
278

279
        // Point to the new super instruction
280
        old[start].op_code = OpCode::DynSuperInstruction;
281
        old[start].payload_size = super_instruction_id as _;
282
        *guard = old.into();
283
        (head_instruction, Shared::clone(&guard))
284
    }
285

286
    #[inline(always)]
287
    pub fn arity(&self) -> usize {
26,186,887✔
288
        self.arity as usize
26,186,887✔
289
    }
290

291
    // pub fn heap_allocated(&self) -> &RefCell<Vec<HeapRef<SteelVal>>> {
292
    //     &self.heap_allocated
293
    // }
294

295
    pub fn captures(&self) -> &[SteelVal] {
8,151,214✔
296
        &self.captures
8,151,214✔
297
    }
298

299
    #[cfg(feature = "dynamic")]
300
    #[inline(always)]
301
    pub fn increment_call_count(&self) {
×
302
        // self.call_count += 1;
303
        self.call_count.set(self.call_count.get() + 1);
×
304
    }
305

306
    #[cfg(feature = "dynamic")]
307
    pub fn call_count(&self) -> usize {
308
        self.call_count.get()
309
    }
310

311
    // pub fn set_cannot_be_compiled(&self) {
312
    //     self.cant_be_compiled.set(true)
313
    // }
314

315
    // pub fn has_attempted_to_be_compiled(&self) -> bool {
316
    //     self.cant_be_compiled.get()
317
    // }
318

319
    pub fn attach_contract_information(&self, steel_struct: Gc<UserDefinedStruct>) {
629✔
320
        #[cfg(feature = "sync")]
321
        {
322
            let mut guard = self.contract.write();
629✔
323

324
            *guard = Some(steel_struct);
629✔
325
        }
326

327
        #[cfg(not(feature = "sync"))]
328
        {
329
            let mut guard = self.contract.borrow_mut();
629✔
330

331
            *guard = Some(steel_struct);
629✔
332
        }
333
    }
334

335
    pub fn get_contract_information(&self) -> Option<SteelVal> {
4,543✔
336
        #[cfg(feature = "sync")]
337
        {
338
            self.contract
4,543✔
339
                .read()
340
                .as_ref()
341
                .map(|x| SteelVal::CustomStruct(x.clone()))
9,315✔
342
        }
343

344
        #[cfg(not(feature = "sync"))]
345
        {
346
            self.contract
4,543✔
347
                .borrow()
348
                .as_ref()
349
                .map(|x| SteelVal::CustomStruct(x.clone()))
4,543✔
350
        }
351
    }
352

353
    // pub fn mark_hot(&self) {
354
    //     self.is_hot.set(true)
355
    // }
356

357
    // pub(crate) fn mark_block_tail(&self, pattern: BlockPattern) {
358
    //     self.blocks.borrow_mut();
359
    // }
360

361
    // pub(crate) fn check_tail(&self, pattern: &BlockPattern) -> bool {
362
    //     self.blocks.borrow().contains(pattern)
363
    // }
364

365
    // pub(crate) fn block_tail(&self, block_pattern
366
}
367

368
pub fn attach_contract_struct(args: &[SteelVal]) -> crate::rvals::Result<SteelVal> {
629✔
369
    if let SteelVal::Closure(closure) = &args[0] {
1,258✔
370
        if let SteelVal::CustomStruct(s) = &args[1] {
629✔
371
            closure.attach_contract_information(s.clone());
629✔
372

373
            Ok(SteelVal::Void)
629✔
374
        } else {
375
            stop!(TypeMismatch => "attach-contract-struct! expects a struct in the second position")
×
376
        }
377
    } else {
378
        stop!(TypeMismatch => "attach-contract-struct! expects a function in the first position")
×
379
    }
380
}
381

382
pub fn get_contract(args: &[SteelVal]) -> crate::rvals::Result<SteelVal> {
726✔
383
    if let SteelVal::Closure(closure) = &args[0] {
1,289✔
384
        closure.get_contract_information().into_steelval()
385
    } else {
386
        Ok(SteelVal::BoolV(false))
163✔
387

388
        // stop!(TypeMismatch => "get-contract-struct! expects a function in the first position, found: {}", &args[0])
389
    }
390
}
391

392
#[derive(Clone)]
393
#[repr(C)]
394
pub enum StaticOrRcStr {
395
    Static(&'static str),
396
    Owned(Arc<String>),
397
}
398

399
/// This allows cloning the underlying closure, so we can send it across threads.
400
/// It does _not_ solve serializing closures fully, but it does mean we can move function
401
/// pointers across threads, which should be very helpful with spawning native threads.
402
// TODO: @Matt - Replace usage of BoxedDynFunction (and subsequent call sites) with this instead
403
// trait DynamicFunction: Send + Sync {
404
//     #[inline]
405
//     fn call(&self, args: &[SteelVal]) -> crate::rvals::Result<SteelVal>;
406
//     fn clone_box(&self) -> Box<dyn DynamicFunction>;
407
// }
408

409
// // Allow only the capturing of send + sync variables?
410
// impl<F: Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Clone + Send + Sync + 'static>
411
//     DynamicFunction for F
412
// {
413
//     fn call(&self, args: &[SteelVal]) -> crate::rvals::Result<SteelVal> {
414
//         (self)(args)
415
//     }
416

417
//     fn clone_box(&self) -> Box<dyn DynamicFunction> {
418
//         Box::new(self.clone())
419
//     }
420
// }
421

422
// impl Clone for Box<dyn DynamicFunction> {
423
//     fn clone(&self) -> Self {
424
//         self.clone_box()
425
//     }
426
// }
427

428
// pub enum MaybeSendSyncFunction {}
429

430
#[derive(Clone)]
431
#[repr(C)]
432
pub struct BoxedDynFunction {
433
    pub function:
434
        Arc<dyn Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Send + Sync + 'static>,
435
    pub name: Option<StaticOrRcStr>,
436
    pub arity: Option<usize>,
437
}
438

439
impl BoxedDynFunction {
440
    // pub fn spawn_on_thread(self) {
441
    //     std::thread::spawn(move || self.function);
442
    // }
443

444
    pub(crate) fn new(
709✔
445
        function: Arc<
446
            dyn Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Send + Sync + 'static,
447
        >,
448
        name: Option<&str>,
449
        arity: Option<usize>,
450
    ) -> Self {
451
        BoxedDynFunction {
452
            function,
453
            name: name
709✔
454
                .map(|x| Arc::new(x.to_string()))
455
                .map(StaticOrRcStr::Owned),
456
            arity,
457
        }
458
    }
459

460
    pub(crate) fn new_owned(
4,510✔
461
        function: Arc<
462
            dyn Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Send + Sync + 'static,
463
        >,
464
        name: Option<Arc<String>>,
465
        arity: Option<usize>,
466
    ) -> Self {
467
        BoxedDynFunction {
468
            function,
469
            name: name.map(StaticOrRcStr::Owned),
4,510✔
470
            arity,
471
        }
472
    }
473

474
    #[inline(always)]
475
    pub fn func(
26,674✔
476
        &self,
477
    ) -> &(dyn Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Send + Sync + 'static) {
478
        self.function.as_ref()
26,674✔
479
    }
480

481
    #[inline(always)]
482
    pub fn get_arity(&self) -> Option<usize> {
×
483
        self.arity
×
484
    }
485

486
    #[inline(always)]
487
    pub fn name(&self) -> Option<&str> {
×
488
        match &self.name {
×
489
            Some(StaticOrRcStr::Owned(o)) => None, // TODO: Come back here @Matt
×
490
            Some(StaticOrRcStr::Static(s)) => Some(s),
×
491
            None => None,
×
492
        }
493
    }
494
}
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