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

Qiskit / qiskit / 26105264432

19 May 2026 02:53PM UTC coverage: 87.694% (+0.007%) from 87.687%
26105264432

Pull #16178

github

web-flow
Merge 9a5f312d8 into 26d7f00c1
Pull Request #16178: Add C API for inspecting classical expressions

360 of 450 new or added lines in 3 files covered. (80.0%)

5 existing lines in 4 files now uncovered.

108438 of 123655 relevant lines covered (87.69%)

949633.17 hits per line

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

86.6
/crates/cext/src/classical_expr.rs
1
use std::ptr;
2

3
use qiskit_circuit::{classical::{expr::{Binary, BinaryOp, Expr, Stretch, UnaryOp, Value, Var, Index, Cast, Unary}, types::Type}, duration::Duration};
4
use uuid::Uuid;
5
use crate::pointers::{const_ptr_as_ref, mut_ptr_as_ref};
6
use num_bigint::BigUint;
7
use std::ffi::{c_char, CString};
8
use num_traits::{ToPrimitive, Zero};
9

10
#[repr(u8)]
11
pub enum CExprNodeKind { 
12
    Unary = 0, 
13
    Binary = 1,
14
    Cast = 2,
15
    Value = 3,
16
    Var = 4, 
17
    Stretch = 5, 
18
    Index = 6,
19
}
20

21
impl From<&Expr> for CExprNodeKind {
22
    fn from(value: &Expr) -> Self {
268✔
23
        match value {
268✔
24
            Expr::Unary(_) => Self::Unary, 
48✔
25
            Expr::Binary(_) => Self::Binary, 
88✔
26
            Expr::Cast(_) => Self::Cast,
20✔
27
            Expr::Index(_) => Self::Index,
20✔
28
            Expr::Stretch(_) => Self::Stretch, 
32✔
29
            Expr::Value(_) => Self::Value,
20✔
30
            Expr::Var(_) => Self::Var,
40✔
31
        }
32
    }
268✔
33
}
34

35
#[repr(u8)]
36
pub enum CExprType {
37
    Bool = 0,
38
    Duration = 1,
39
    Float = 2,
40
    Uint = 3,
41
}
42

43
impl From<&Type> for CExprType {
44
    fn from(value: &Type) -> Self {
28✔
45
        match value {
28✔
46
            Type::Bool => Self::Bool,
8✔
47
            Type::Duration => Self::Duration,
4✔
48
            Type::Float => Self::Float,
8✔
49
            Type::Uint(_) => Self::Uint,
8✔
50
        }
51
    }
28✔
52
}
53

54
impl From<&Value> for CExprType {
55
    fn from(value: &Value) -> Self {
16✔
56
        match value {
16✔
57
            Value::Duration(_) => Self::Duration,
4✔
58
            Value::Float { ty, .. } => Self::from(ty),
4✔
59
            Value::Uint { ty, .. } => Self::from(ty),
8✔
60
        }
61
    }
16✔
62
}
63

64
#[repr(C)]
65
pub struct CExprTypeInfo {
66
    ty: CExprType,
67
    width: u16,
68
}
69

70
impl CExprTypeInfo {
71
    fn to_type(&self) -> Type {
224✔
72
        match self.ty {
224✔
73
            CExprType::Bool => Type::Bool,
56✔
74
            CExprType::Duration => Type::Duration,
56✔
75
            CExprType::Float => Type::Float,
56✔
76
            CExprType::Uint => Type::Uint(self.width),
56✔
77
        }
78
    }
224✔
79
}
80

81
impl From<&Type> for CExprTypeInfo {
82
    fn from(ty: &Type) -> Self {
176✔
83
        match ty {
176✔
84
            Type::Bool => CExprTypeInfo{ty: CExprType::Bool, width: 0},
32✔
85
            Type::Duration => CExprTypeInfo{ty: CExprType::Duration, width: 0},
20✔
86
            Type::Float => CExprTypeInfo{ty: CExprType::Float, width: 0},
100✔
87
            Type::Uint(w) => CExprTypeInfo{ty: CExprType::Uint, width: *w},
24✔
88
        }
89
    }
176✔
90
}
91

92

93
#[repr(u8)]
94
pub enum CUnaryOpType {
95
    BitNot = 1, // TODO: keeping it one-based on purpose, to avoid confusion with the convention in Python
96
    LogicNot = 2,
97
    Negate = 3,
98
}
99

100
impl From<UnaryOp> for CUnaryOpType {
101
    fn from(value: UnaryOp) -> Self {
48✔
102
        match value { 
48✔
103
        UnaryOp::BitNot => Self::BitNot,
36✔
104
        UnaryOp::LogicNot => Self::LogicNot,
8✔
105
        UnaryOp::Negate => Self::Negate,
4✔
106
        }
107
    }
48✔
108
}
109

110
impl CUnaryOpType {
111
    fn to_unary_op(self) -> UnaryOp {
12✔
112
        match self {
12✔
113
            CUnaryOpType::BitNot => UnaryOp::BitNot,
4✔
114
            CUnaryOpType::LogicNot => UnaryOp::LogicNot,
4✔
115
            CUnaryOpType::Negate => UnaryOp::Negate,
4✔
116
        }
117
    }
12✔
118
}
119

120
#[repr(C)]
121
pub struct CUnaryExprInfo {
122
    pub op: CUnaryOpType,
123
    pub operand: *const Expr,
124
    pub ty: CExprTypeInfo,
125
    pub constant: bool,
126
}
127

128
#[repr(u8)]
129
pub enum CBinaryOpType {
130
    BitAnd = 1, // TODO: keeping it one-based on purpose, to avoid confusion with the convention in Python
131
    BitOr = 2,
132
    BitXor = 3,
133
    LogicAnd = 4,
134
    LogicOr = 5,
135
    Equal = 6,
136
    NotEqual = 7,
137
    Less = 8,
138
    LessEqual = 9,
139
    Greater = 10,
140
    GreaterEqual = 11,
141
    ShiftLeft = 12,
142
    ShiftRight = 13,
143
    Add = 14,
144
    Sub = 15,
145
    Mul = 16,
146
    Div = 17,
147
}
148

149
impl From<BinaryOp> for CBinaryOpType {
150
    fn from(value: BinaryOp) -> Self {
88✔
151
        match value {
88✔
152
            BinaryOp::BitAnd => Self::BitAnd,
20✔
153
            BinaryOp::BitOr => Self::BitOr,
4✔
154
            BinaryOp::BitXor => Self::BitXor,
4✔
155
            BinaryOp::LogicAnd => Self::LogicAnd,
4✔
156
            BinaryOp::LogicOr => Self::LogicOr,
4✔
157
            BinaryOp::Equal => Self::Equal,
4✔
158
            BinaryOp::NotEqual => Self::NotEqual,
4✔
159
            BinaryOp::Less => Self::Less,
4✔
160
            BinaryOp::LessEqual => Self::LessEqual,
4✔
161
            BinaryOp::Greater => Self::Greater,
8✔
162
            BinaryOp::GreaterEqual => Self::GreaterEqual,
4✔
163
            BinaryOp::ShiftLeft => Self::ShiftLeft,
4✔
164
            BinaryOp::ShiftRight => Self::ShiftRight,
4✔
165
            BinaryOp::Add => Self::Add,
4✔
166
            BinaryOp::Sub => Self::Sub,
4✔
167
            BinaryOp::Mul => Self::Mul,
4✔
168
            BinaryOp::Div => Self::Div,
4✔
169
        }
170
    }
88✔
171
}
172

173
impl CBinaryOpType {
174
    fn to_binary_op(self) -> BinaryOp {
68✔
175
        match self {
68✔
176
            CBinaryOpType::BitAnd => BinaryOp::BitAnd,
4✔
177
            CBinaryOpType::BitOr => BinaryOp::BitOr,
4✔
178
            CBinaryOpType::BitXor => BinaryOp::BitXor,
4✔
179
            CBinaryOpType::LogicAnd => BinaryOp::LogicAnd,
4✔
180
            CBinaryOpType::LogicOr => BinaryOp::LogicOr,
4✔
181
            CBinaryOpType::Equal => BinaryOp::Equal,
4✔
182
            CBinaryOpType::NotEqual => BinaryOp::NotEqual,
4✔
183
            CBinaryOpType::Less => BinaryOp::Less,
4✔
184
            CBinaryOpType::LessEqual => BinaryOp::LessEqual,
4✔
185
            CBinaryOpType::Greater => BinaryOp::Greater,
4✔
186
            CBinaryOpType::GreaterEqual => BinaryOp::GreaterEqual,
4✔
187
            CBinaryOpType::ShiftLeft => BinaryOp::ShiftLeft,
4✔
188
            CBinaryOpType::ShiftRight => BinaryOp::ShiftRight,
4✔
189
            CBinaryOpType::Add => BinaryOp::Add,
4✔
190
            CBinaryOpType::Sub => BinaryOp::Sub,
4✔
191
            CBinaryOpType::Mul => BinaryOp::Mul,
4✔
192
            CBinaryOpType::Div => BinaryOp::Div,
4✔
193
        }
194
    }
68✔
195
}
196

197
#[repr(C)]
198
pub struct CBinaryExprInfo {
199
    pub op: CBinaryOpType,
200
    pub left: *const Expr,
201
    pub right: *const Expr,
202
    pub ty: CExprTypeInfo,
203
    pub constant: bool,
204
}
205

206
#[repr(C)]
207
pub struct CCastExprInfo {
208
    pub operand: *const Expr,
209
    pub ty: CExprTypeInfo,
210
    pub implicit: bool,
211
    pub constant: bool,
212
}
213

214
#[repr(C)]
215
pub struct CIndexExprInfo {
216
    pub target: *const Expr,
217
    pub index: *const Expr,
218
    pub ty: CExprTypeInfo,
219
    pub constant: bool,
220
}
221

222
#[repr(u8)]
223
pub enum CDurationType {
224
    Dt = 0,
225
    Ps = 1,
226
    Ns = 2,
227
    Us = 3,
228
    Ms = 4,
229
    S = 5, 
230
}
231

232
impl From<&Duration> for CDurationType {
NEW
233
    fn from(duration: &Duration) -> Self {
×
NEW
234
        match duration {
×
NEW
235
            Duration::dt(_) => Self::Dt,
×
NEW
236
            Duration::ps(_) => Self::Ps,
×
NEW
237
            Duration::ns(_) => Self::Ns,
×
NEW
238
            Duration::us(_) => Self::Us,
×
NEW
239
            Duration::ms(_) => Self::Ms,
×
NEW
240
            Duration::s(_) => Self::S,
×
241
        }
NEW
242
    }
×
243
}
244

245
#[repr(C)]
246
pub union CDurationValue {
247
    dt: i64,
248
    time: f64,
249
}
250

251
#[repr(C)]
252
pub struct CDurationInfo {
253
    pub ty: CDurationType,
254
    pub value: CDurationValue,
255
}
256

257
impl From<&Duration> for CDurationInfo {
258
    fn from(duration: &Duration) -> Self {
4✔
259
        match duration {
4✔
260
            Duration::dt(v) => CDurationInfo {
4✔
261
                ty: CDurationType::Dt,
4✔
262
                value: CDurationValue{dt: *v},
4✔
263
            },
4✔
NEW
264
            Duration::ps(v) => CDurationInfo {
×
NEW
265
                ty: CDurationType::Ps,
×
NEW
266
                value: CDurationValue{time: *v},
×
NEW
267
            },
×
NEW
268
            Duration::ns(v) => CDurationInfo {
×
NEW
269
                ty: CDurationType::Ns,
×
NEW
270
                value: CDurationValue{time: *v},
×
NEW
271
            },
×
NEW
272
            Duration::us(v) => CDurationInfo {
×
NEW
273
                ty: CDurationType::Us,
×
NEW
274
                value: CDurationValue{time: *v},
×
NEW
275
            },
×
NEW
276
            Duration::ms(v) => CDurationInfo {
×
NEW
277
                ty: CDurationType::Ms,
×
NEW
278
                value: CDurationValue{time: *v},
×
NEW
279
            },
×
NEW
280
            Duration::s(v) => CDurationInfo {
×
NEW
281
                ty: CDurationType::S,
×
NEW
282
                value: CDurationValue{time: *v},
×
NEW
283
            },
×
284
        }
285
    }
4✔
286
}
287

288
impl CDurationInfo {
289
    pub fn to_duration(&self) -> Duration {
4✔
290
        match self.ty {
4✔
291
            CDurationType::Dt => Duration::dt(unsafe{self.value.dt}),
4✔
NEW
292
            CDurationType::Ps => Duration::ps(unsafe{self.value.time}),
×
NEW
293
            CDurationType::Ns => Duration::ns(unsafe{self.value.time}),
×
NEW
294
            CDurationType::Us => Duration::us(unsafe{self.value.time}),
×
NEW
295
            CDurationType::Ms => Duration::ms(unsafe{self.value.time}),
×
NEW
296
            CDurationType::S => Duration::s(unsafe{self.value.time}),
×
297
        }
298
    }
4✔
299
}
300

301

302
#[unsafe(no_mangle)]
303
pub unsafe extern "C" fn qk_expr_node_kind(expr: *const Expr) -> CExprNodeKind {
268✔
304
    let expr = unsafe{ const_ptr_as_ref(expr) };
268✔
305

306
    CExprNodeKind::from(expr)
268✔
307
}
268✔
308

309
#[unsafe(no_mangle)]
310
pub unsafe extern "C" fn qk_expr_binary_info(expr: *const Expr) -> CBinaryExprInfo {
88✔
311
    let expr = unsafe{ const_ptr_as_ref(expr) };
88✔
312

313
    let Expr::Binary(binary) = expr else {
88✔
NEW
314
        panic!("TODO")
×
315
    };
316

317
    CBinaryExprInfo {
88✔
318
        op: CBinaryOpType::from(binary.op),
88✔
319
        left: &binary.left as *const Expr,
88✔
320
        right: &binary.right as *const Expr,
88✔
321
        ty: CExprTypeInfo::from(&binary.ty),
88✔
322
        constant: binary.constant,
88✔
323
    }
88✔
324
}
88✔
325

326
#[unsafe(no_mangle)]
327
pub unsafe extern "C" fn qk_expr_unary_info(expr: *const Expr) -> CUnaryExprInfo {
48✔
328
    let expr = unsafe { const_ptr_as_ref(expr) };
48✔
329

330
    let Expr::Unary(unary) = expr else {
48✔
NEW
331
        panic!("TODO")
×
332
    };
333

334
    CUnaryExprInfo {
48✔
335
        op: CUnaryOpType::from(unary.op),
48✔
336
        operand: &unary.operand as *const Expr,
48✔
337
        ty: CExprTypeInfo::from(&unary.ty),
48✔
338
        constant: unary.constant,
48✔
339
    }
48✔
340
}
48✔
341

342
#[unsafe(no_mangle)]
343
pub unsafe extern "C" fn qk_expr_cast_info(expr: *const Expr) -> CCastExprInfo {
20✔
344
    let expr = unsafe { const_ptr_as_ref(expr) };
20✔
345

346
    let Expr::Cast(cast) = expr else {
20✔
NEW
347
        panic!("TODO")
×
348
    };
349

350
    CCastExprInfo {
20✔
351
        operand: &cast.operand as *const Expr,
20✔
352
        ty: CExprTypeInfo::from(&cast.ty),
20✔
353
        implicit: cast.implicit,
20✔
354
        constant: cast.constant,
20✔
355
    }
20✔
356
}
20✔
357

358
#[unsafe(no_mangle)]
359
pub unsafe extern "C" fn qk_expr_index_info(expr: *const Expr) -> CIndexExprInfo {
20✔
360
    let expr = unsafe { const_ptr_as_ref(expr) };
20✔
361

362
    let Expr::Index(index) = expr else {
20✔
NEW
363
        panic!("TODO")
×
364
    };
365

366
    CIndexExprInfo {
20✔
367
        target: &index.target as *const Expr,
20✔
368
        index: &index.index as *const Expr,
20✔
369
        ty: CExprTypeInfo::from(&index.ty),
20✔
370
        constant: index.constant,
20✔
371
    }
20✔
372
}
20✔
373

374
#[unsafe(no_mangle)]
375
pub unsafe extern "C" fn qk_expr_as_value(expr: *const Expr) -> *const Value {
16✔
376
    let expr = unsafe { const_ptr_as_ref(expr) };
16✔
377

378
    let Expr::Value(val) = expr else {
16✔
NEW
379
        panic!("TODO")
×
380
    };
381

382
    val as *const Value
16✔
383
}
16✔
384

385
#[unsafe(no_mangle)]
386
pub unsafe extern "C" fn qk_expr_as_var(expr: *const Expr) -> *const Var {
16✔
387
    let expr = unsafe { const_ptr_as_ref(expr) };
16✔
388

389
    let Expr::Var(var) = expr else {
16✔
NEW
390
        panic!("TODO")
×
391
    };
392

393
    ptr::from_ref(var)
16✔
394
}
16✔
395

396
#[unsafe(no_mangle)]
397
pub unsafe extern "C" fn qk_expr_as_stretch(expr: *const Expr) -> *const Stretch {
16✔
398
    let expr = unsafe { const_ptr_as_ref(expr) };
16✔
399

400
    let Expr::Stretch(stretch) = expr else {
16✔
NEW
401
        panic!("TODO")
×
402
    };
403

404
    ptr::from_ref(stretch)
16✔
405
}
16✔
406

407

408
#[unsafe(no_mangle)]
409
pub unsafe extern "C" fn qk_value_type(value: *const Value) -> CExprType { 
16✔
410
    let value = unsafe { const_ptr_as_ref(value) };
16✔
411
    
412
    CExprType::from(value)
16✔
413
}
16✔
414

415
#[unsafe(no_mangle)]
416
pub unsafe extern "C" fn qk_value_duration_info(value: *const Value) -> CDurationInfo {
4✔
417
    let value = unsafe { const_ptr_as_ref(value) };
4✔
418
    
419
    let Value::Duration(duration) = value else {
4✔
NEW
420
        panic!("TODO")
×
421
    };
422
    
423
    CDurationInfo::from(duration)
4✔
424
}
4✔
425

426
#[unsafe(no_mangle)]
427
pub unsafe extern "C" fn qk_value_float(value: *const Value) -> f64{
4✔
428
    let value = unsafe { const_ptr_as_ref(value) };
4✔
429
    
430
    let Value::Float{raw, ..} = value else { // TODO: what should we do with ty?
4✔
NEW
431
        panic!("TODO")
×
432
    };
433

434
    *raw
4✔
435
}
4✔
436

437
#[unsafe(no_mangle)]
438
pub unsafe extern "C" fn qk_value_uint(value: *const Value) -> u64 {
4✔
439
    let value = unsafe { const_ptr_as_ref(value) };
4✔
440
    
441
    let Value::Uint { raw, ty: Type::Uint(_) } = value else {
4✔
NEW
442
        panic!("TODO")
×
443
    };
444

445
    raw.to_u64()
4✔
446
        .expect("TODO") // TODO: handle BigUint. Is there a better way?
4✔
447
}
4✔
448

449
#[unsafe(no_mangle)]
450
pub unsafe extern "C" fn qk_value_bool(value: *const Value) -> bool {
4✔
451
    let value = unsafe { const_ptr_as_ref(value) };
4✔
452
    
453
    let Value::Uint { raw, ty: Type::Bool } = value else {
4✔
NEW
454
        panic!("TODO")
×
455
    };
456

457
    !raw.is_zero()
4✔
458
}
4✔
459

460

461
#[unsafe(no_mangle)]
462
pub unsafe extern "C" fn qk_var_name(var: *const Var) -> *mut c_char {
16✔
463
    let var = unsafe { const_ptr_as_ref(var) };
16✔
464

465
    let name = match var {
16✔
466
        Var::Standalone { name, .. } => name.as_str(),
16✔
NEW
467
        Var::Register { register, .. } => register.name(),
×
NEW
468
        Var::Bit { .. } => return ptr::null_mut(),
×
469
    };
470

471
    CString::new(name)
16✔
472
        .map_or(std::ptr::null_mut(), |name| name.into_raw()) // TODO: panic if name can't be constructed?
16✔
473
}
16✔
474

475
#[unsafe(no_mangle)]
476
pub unsafe extern "C" fn qk_var_type_info(var: *const Var) -> CExprTypeInfo {
16✔
477
    let var = unsafe { const_ptr_as_ref(var) };
16✔
478

479
    let ty = match var {
16✔
480
        Var::Standalone { ty, .. } => ty,
16✔
NEW
481
        Var::Register { ty, ..} => ty,
×
NEW
482
        Var::Bit { .. } => panic!("TODO"),
×
483
    };
484

485
    let width = if let Type::Uint(width) = ty {*width} else {0u16};
16✔
486

487
    CExprTypeInfo{ty: CExprType::from(ty), width: width}
16✔
488
}
16✔
489

490
#[unsafe(no_mangle)]
491
pub unsafe extern "C" fn qk_var_as_expr(var: *const Var) -> *mut Expr {
16✔
492
    let var = unsafe{ const_ptr_as_ref(var) };
16✔
493

494
    Box::into_raw(Box::new(Expr::Var(var.clone())))
16✔
495
}
16✔
496

497
#[unsafe(no_mangle)]
498
pub unsafe extern "C" fn qk_stretch_name(stretch: *const Stretch) -> *mut c_char {
16✔
499
    let stretch = unsafe { const_ptr_as_ref(stretch) };
16✔
500
    
501
    CString::new(stretch.name.as_str())
16✔
502
        .map_or(std::ptr::null_mut(), |name| name.into_raw()) // TODO: panic if name can't be constructed?
16✔
503
}
16✔
504

505
#[unsafe(no_mangle)]
506
pub unsafe extern "C" fn qk_stretch_as_expr(stretch: *const Stretch) -> *mut Expr {
16✔
507
    let stretch = unsafe { const_ptr_as_ref(stretch) };
16✔
508

509
    Box::into_raw(Box::new(Expr::Stretch(stretch.clone())))
16✔
510
}
16✔
511

512
#[unsafe(no_mangle)]
513
pub unsafe extern "C" fn qk_expr_free(expr: *mut Expr) {
212✔
514
    drop(unsafe{ Box::from_raw(expr) })
212✔
515
}
212✔
516

517

518
/// cbindgen:no-export
519
#[unsafe(no_mangle)]
520
pub unsafe extern "C" fn inner_test_expression_structs() -> *mut Expr {
4✔
521
    let v1 = Expr::Var(Var::Standalone {
4✔
522
        uuid: Uuid::new_v4().as_u128(),
4✔
523
        name: "v1".to_owned(),
4✔
524
        ty: Type::Uint(3),
4✔
525
    });
4✔
526

527
    let five = Expr::Value(Value::Uint {
4✔
528
        raw: BigUint::from(5u32),
4✔
529
        ty: Type::Uint(3),
4✔
530
    });
4✔
531

532
    let gt = Expr::Binary(Box::new(Binary {
4✔
533
        op: BinaryOp::Greater,
4✔
534
        left: v1.clone(),
4✔
535
        right: five,
4✔
536
        ty: Type::Bool,
4✔
537
        constant: false,
4✔
538
    }));
4✔
539

540
    let lt_eq = Expr::Unary(Box::new(Unary {
4✔
541
        op: UnaryOp::LogicNot,
4✔
542
        operand: gt,
4✔
543
        ty: Type::Bool,
4✔
544
        constant: false,
4✔
545
    }));
4✔
546

547
    let idx = Expr::Cast(Box::new(Cast {
4✔
548
        operand: lt_eq,
4✔
549
        ty: Type::Uint(1),
4✔
550
        implicit: false,
4✔
551
        constant: false,
4✔
552
    }));
4✔
553

554
    let index = Expr::Index(Box::new(Index {
4✔
555
        target: v1,
4✔
556
        index: idx,
4✔
557
        ty: Type::Bool,
4✔
558
        constant: false,
4✔
559
    }));
4✔
560

561
    Box::into_raw(Box::new(index))
4✔
562
}
4✔
563

564
/// cbindgen:no-export
565
#[unsafe(no_mangle)]
566
pub unsafe extern "C" fn inner_test_binary_expr_ops(op: CBinaryOpType) -> *mut Expr {
68✔
567
    let zero = Expr::Value(Value::Float { raw: 0.0, ty: Type::Float });
68✔
568

569
    let expr = Expr::Binary(Box::new(Binary { op: op.to_binary_op(), left: zero.clone(), right: zero.clone(), ty: Type::Float, constant: true }));
68✔
570

571
    Box::into_raw(Box::new(expr))
68✔
572
}
68✔
573

574
/// cbindgen:no-export
575
#[unsafe(no_mangle)]
576
pub unsafe extern "C" fn inner_test_unary_expr_ops(op: CUnaryOpType) -> *mut Expr {
12✔
577
    let zero = Expr::Value(Value::Float { raw: 0.0, ty: Type::Float });
12✔
578

579
    let expr = Expr::Unary(Box::new(Unary { op: op.to_unary_op(), operand: zero, ty: Type::Float, constant: true }));
12✔
580

581
    Box::into_raw(Box::new(expr))
12✔
582
}
12✔
583

584
/// cbindgen:no-export
585
#[unsafe(no_mangle)]
586
pub unsafe extern "C" fn inner_test_expr_kinds_and_types(kind: CExprNodeKind, ty: CExprTypeInfo) -> *mut Expr {
112✔
587
    let rust_type = ty.to_type();
112✔
588
    
589
    let dummy_value = match &rust_type {
112✔
590
        Type::Bool => Expr::Value(Value::Uint { raw: BigUint::from(0u32), ty: Type::Bool }),
28✔
591
        Type::Duration => Expr::Value(Value::Duration(Duration::dt(0))),
28✔
592
        Type::Float => Expr::Value(Value::Float { raw: 0.0, ty: Type::Float }),
28✔
593
        Type::Uint(w) => Expr::Value(Value::Uint { raw: BigUint::from(0u32), ty: Type::Uint(*w) }),
28✔
594
    };
595

596
    let var = Expr::Var(Var::Standalone {
112✔
597
            uuid: Uuid::new_v4().as_u128(),
112✔
598
            name: "test_var".to_owned(),
112✔
599
            ty: ty.to_type(),
112✔
600
        });
112✔
601

602
    let index = Expr::Value(Value::Uint { raw: BigUint::from(0u32), ty: Type::Uint(3) });
112✔
603

604
    let expr = match kind {
112✔
605
        CExprNodeKind::Unary => {
606
            Expr::Unary(Box::new(Unary {
32✔
607
                op: UnaryOp::BitNot,
32✔
608
                operand: dummy_value,
32✔
609
                ty: rust_type,
32✔
610
                constant: true,
32✔
611
            }))
32✔
612
        }
613
        CExprNodeKind::Binary => {
614
            Expr::Binary(Box::new(Binary {
16✔
615
                op: BinaryOp::BitAnd,
16✔
616
                left: dummy_value.clone(),
16✔
617
                right: dummy_value,
16✔
618
                ty: rust_type,
16✔
619
                constant: true,
16✔
620
            }))
16✔
621
        }
622
        CExprNodeKind::Cast => {
623
            Expr::Cast(Box::new(Cast {
16✔
624
                operand: dummy_value,
16✔
625
                ty: rust_type,
16✔
626
                implicit: false,
16✔
627
                constant: true,
16✔
628
            }))
16✔
629
        }
630
        CExprNodeKind::Index => {
631
            Expr::Index(Box::new(Index {
16✔
632
                target: var,
16✔
633
                index,
16✔
634
                ty: rust_type,
16✔
635
                constant: false,
16✔
636
            }))
16✔
637
        }
NEW
638
        CExprNodeKind::Value => dummy_value,
×
639
        CExprNodeKind::Var => {
640
            var
16✔
641
        }
642
        CExprNodeKind::Stretch => {
643
            Expr::Stretch(Stretch {
16✔
644
                uuid: Uuid::new_v4().as_u128(),
16✔
645
                name: "test_stretch".to_owned(),
16✔
646
            })
16✔
647
        }
648
    };
649
    
650
    Box::into_raw(Box::new(expr))
112✔
651
}
112✔
652

653
/// cbindgen:no-export
654
#[unsafe(no_mangle)]
655
pub unsafe extern "C" fn inner_test_value(ty: CExprType, b: bool, duration: CDurationInfo, f_val: f64, u_val: u64) -> *mut Expr {
16✔
656
    let value = match ty {
16✔
657
        CExprType::Bool => {
658
            Value::Uint {
659
                raw: BigUint::from(if b { 1u32 } else { 0u32 }),
4✔
660
                ty: Type::Bool,
4✔
661
            }
662
        }
663
        CExprType::Duration => {
664
            Value::Duration(duration.to_duration())
4✔
665
        }
666
        CExprType::Float => {
667
            Value::Float {
4✔
668
                raw: f_val,
4✔
669
                ty: Type::Float,
4✔
670
            }
4✔
671
        }
672
        CExprType::Uint => {
673
            Value::Uint {
4✔
674
                raw: BigUint::from(u_val),
4✔
675
                ty: Type::Uint(4),
4✔
676
            }
4✔
677
        }
678
    };
679
    
680
    Box::into_raw(Box::new(Expr::Value(value)))
16✔
681
}
16✔
682

683

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

© 2026 Coveralls, Inc