1use quickcheck::{Arbitrary, Gen, StdGen};
2use rand::thread_rng;
3use std::fmt;
4
5/// BaseTypeC is used in generation of C headers to represent the C language's
6/// primitive types as well as `void*`.
7#[derive(Debug, Clone)]
8pub struct BaseTypeC {
9    /// String representation of C type.
10    pub def: String,
11}
12
13/// TypeQualifierC is used in generation of C headers to represent qualifiers
14/// such as `const`.
15#[derive(Debug, Clone)]
16pub struct TypeQualifierC {
17    /// String representation of C type qualifier.
18    pub def: String,
19}
20
21/// PointerLevelC is used in generation of C headers to represent number of
22/// `*` for pointer types.
23#[derive(Debug, Clone)]
24pub struct PointerLevelC {
25    /// String representation of C declaration's pointer level.
26    pub def: String,
27}
28
29/// ArrayDimensionC is used in generation of C headers to represent number of
30/// `[]` used to define array types.
31#[derive(Debug, Clone)]
32pub struct ArrayDimensionC {
33    /// String representation of C declaration's array dimension.
34    pub def: String,
35}
36
37/// BasicTypeDeclarationC is used in generation of C headers to represent
38/// declarations outside of function pointers that take the form
39/// `BaseTypeC` + `TypeQualifierC` + `PointerLevelC` + `ident_id`.
40#[derive(Debug, Clone)]
41pub struct BasicTypeDeclarationC {
42    /// The declaration's base type, i.e. `int`.
43    pub type_name: BaseTypeC,
44    /// The declaration's type qualifier, i.e. `const`.
45    pub type_qualifier: TypeQualifierC,
46    /// The declaration's pointer level, i.e. `***`.
47    pub pointer_level: PointerLevelC,
48    /// The declaration's array dimension, i.e. [][][].
49    pub array_dimension: ArrayDimensionC,
50    /// The declaration's identifier, i.e. ident_N.
51    pub ident_id: String,
52}
53
54/// StructDeclarationC is used in generation of C headers to represent the
55/// definition of a struct type.
56#[derive(Debug, Clone)]
57pub struct StructDeclarationC {
58    /// The declaration's fields.
59    pub fields: DeclarationListC,
60    /// The declaration's array dimension, i.e. [][][].
61    pub array_dimension: ArrayDimensionC,
62    /// The declaration's identifier, i.e. struct_N.
63    pub ident_id: String,
64}
65
66/// UnionDeclarationC is used in generation of C headers to represent the
67/// definition of a union type.
68#[derive(Debug, Clone)]
69pub struct UnionDeclarationC {
70    /// The declaration's fields.
71    pub fields: DeclarationListC,
72    /// The declaration's array dimension, i.e. [][][].
73    pub array_dimension: ArrayDimensionC,
74    /// The declaration's identifier, i.e. union_N.
75    pub ident_id: String,
76}
77
78/// FunctionPointerDeclarationC is used in generation of C headers to represent
79/// the definition of a function pointer type.
80#[derive(Debug, Clone)]
81pub struct FunctionPointerDeclarationC {
82    /// The function's type qualifier, i.e. `const`.
83    pub type_qualifier: TypeQualifierC,
84    /// The function's return type, i.e. `int`.
85    pub type_name: BaseTypeC,
86    /// The function's pointer level, i.e. `***`.
87    pub pointer_level: PointerLevelC,
88    /// The function's parameters.
89    pub params: ParameterListC,
90    /// The declaration's identifier, i.e. func_ptr_N.
91    pub ident_id: String,
92}
93
94/// FunctionPrototypeC is used in generation of C headers to represent the
95/// definition of a function prototype.
96#[derive(Debug, Clone)]
97pub struct FunctionPrototypeC {
98    /// The function's type qualifier, i.e. `const`.
99    pub type_qualifier: TypeQualifierC,
100    /// The function's return type, i.e. `int`.
101    pub type_name: BaseTypeC,
102    /// The function's pointer level, i.e. `***`.
103    pub pointer_level: PointerLevelC,
104    /// The function's parameters.
105    pub params: ParameterListC,
106    /// The prototype's identifier, i.e. `func_N`.
107    pub ident_id: String,
108}
109
110/// ParameterC is used in generation of C headers to represent the
111/// definition function parameters.
112#[derive(Debug, Clone)]
113pub struct ParameterC {
114    /// The parameter's type qualifier, i.e. `const`.
115    pub type_qualifier: TypeQualifierC,
116    /// The parameter's base type, i.e. `int`.
117    pub type_name: BaseTypeC,
118    /// The parameter's pointer level, i.e. `***`.
119    pub pointer_level: PointerLevelC,
120}
121
122/// ParameterListC is used in generation of C headers to represent a list of
123/// definitions of function parameters.
124#[derive(Debug, Clone)]
125pub struct ParameterListC {
126    /// Parameters that define a C function signature.
127    pub params: Vec<ParameterC>,
128}
129
130/// DeclarationC is used in generation of C headers to represent all supported
131/// C type declarations allowed in the generated header.
132#[derive(Debug, Clone)]
133pub enum DeclarationC {
134    /// Function prototype declaration kind.
135    FunctionDecl(FunctionPrototypeC),
136    /// Function pointer declaration kind.
137    FunctionPtrDecl(FunctionPointerDeclarationC),
138    /// Struct declaration kind.
139    StructDecl(StructDeclarationC),
140    /// Union declaration kind.
141    UnionDecl(UnionDeclarationC),
142    /// Basic type declaration kind.
143    VariableDecl(BasicTypeDeclarationC),
144}
145
146/// DeclarationListC is used in generation of C headers to represent a list of
147/// declarations.
148#[derive(Debug, Clone)]
149pub struct DeclarationListC {
150    /// Grouping of C declarations.
151    pub decls: Vec<DeclarationC>,
152}
153
154/// HeaderC is used in generation of C headers to represent a collection of
155/// declarations.
156#[derive(Clone)]
157pub struct HeaderC {
158    /// The header's declarations.
159    pub def: DeclarationListC,
160}
161
162/// MakeUnique is used in generation of C headers to make declaration
163/// identifiers unique by incorporating the `stamp` parameter into it's name.
164trait MakeUnique {
165    fn make_unique(&mut self, stamp: usize);
166}
167
168/// MakeUnique is used in generation of C headers to make DeclarationC
169/// identifiers unique.
170impl MakeUnique for DeclarationC {
171    fn make_unique(&mut self, stamp: usize) {
172        match *self {
173            DeclarationC::FunctionDecl(ref mut d) => d.make_unique(stamp),
174            DeclarationC::FunctionPtrDecl(ref mut d) => d.make_unique(stamp),
175            DeclarationC::StructDecl(ref mut d) => d.make_unique(stamp),
176            DeclarationC::UnionDecl(ref mut d) => d.make_unique(stamp),
177            DeclarationC::VariableDecl(ref mut d) => d.make_unique(stamp),
178        }
179    }
180}
181
182/// A qucickcheck trait for describing how DeclarationC types can be
183/// randomly generated and shrunk.
184impl Arbitrary for DeclarationC {
185    fn arbitrary<G: Gen>(g: &mut G) -> DeclarationC {
186        match g.gen_range(0, 5) {
187            0 => DeclarationC::FunctionDecl(FunctionPrototypeC::arbitrary(g)),
188            1 => DeclarationC::FunctionPtrDecl(
189                FunctionPointerDeclarationC::arbitrary(g),
190            ),
191            2 => DeclarationC::StructDecl(StructDeclarationC::arbitrary(g)),
192            3 => DeclarationC::UnionDecl(UnionDeclarationC::arbitrary(g)),
193            4 => {
194                DeclarationC::VariableDecl(BasicTypeDeclarationC::arbitrary(g))
195            }
196            _ => unreachable!(),
197        }
198    }
199}
200
201/// Enables to string and format for DeclarationC types.
202impl fmt::Display for DeclarationC {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        match *self {
205            DeclarationC::FunctionPtrDecl(ref d) => write!(f, "{}", d),
206            DeclarationC::StructDecl(ref d) => write!(f, "{}", d),
207            DeclarationC::UnionDecl(ref d) => write!(f, "{}", d),
208            DeclarationC::VariableDecl(ref d) => write!(f, "{}", d),
209            DeclarationC::FunctionDecl(ref d) => write!(f, "{}", d),
210        }
211    }
212}
213
214/// A qucickcheck trait for describing how DeclarationListC types can be
215/// randomly generated and shrunk.
216impl Arbitrary for DeclarationListC {
217    fn arbitrary<G: Gen>(g: &mut G) -> DeclarationListC {
218        DeclarationListC {
219            decls: Arbitrary::arbitrary(g),
220        }
221    }
222}
223
224/// Enables to string and format for DeclarationListC types.
225impl fmt::Display for DeclarationListC {
226    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227        let mut display = String::new();
228        for decl in &self.decls {
229            display += &format!("{}", decl);
230        }
231        write!(f, "{}", display)
232    }
233}
234
235/// A qucickcheck trait for describing how BaseTypeC types can be
236/// randomly generated and shrunk.
237impl Arbitrary for BaseTypeC {
238    fn arbitrary<G: Gen>(g: &mut G) -> BaseTypeC {
239        // Special case `long double` until issue #550 is resolved.
240        let base_type = vec![
241            "char",
242            "signed char",
243            "unsigned char",
244            "short",
245            "short int",
246            "signed short",
247            "signed short int",
248            "unsigned short",
249            "unsigned short int",
250            "int",
251            "signed",
252            "signed int",
253            "unsigned",
254            "unsigned int",
255            "long",
256            "long int",
257            "signed long",
258            "signed long int",
259            "unsigned long",
260            "unsigned long int",
261            "long long",
262            "long long int",
263            "signed long long",
264            "signed long long int",
265            "unsigned long long",
266            "unsigned long long int",
267            "float",
268            "double",
269            #[cfg(feature = "long-doubles")]
270            "long double",
271            "void*",
272        ];
273        BaseTypeC {
274            def: String::from(*g.choose(&base_type).unwrap()),
275        }
276    }
277}
278
279/// Enables to string and format for BaseTypeC types,
280impl fmt::Display for BaseTypeC {
281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        write!(f, "{}", self.def)
283    }
284}
285
286/// A qucickcheck trait for describing how TypeQualifierC types can be
287/// randomly generated and shrunk.
288impl Arbitrary for TypeQualifierC {
289    fn arbitrary<G: Gen>(g: &mut G) -> TypeQualifierC {
290        let qualifier = vec!["const", ""];
291        TypeQualifierC {
292            def: String::from(*g.choose(&qualifier).unwrap()),
293        }
294    }
295}
296
297/// Enables to string and format for TypeQualifierC types.
298impl fmt::Display for TypeQualifierC {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        write!(f, "{}", self.def)
301    }
302}
303
304/// A qucickcheck trait for describing how PointerLevelC types can be
305/// randomly generated and shrunk.
306impl Arbitrary for PointerLevelC {
307    fn arbitrary<G: Gen>(g: &mut G) -> PointerLevelC {
308        PointerLevelC {
309            // 16 is an arbitrary "not too big" number for capping pointer level.
310            def: (0..g.gen_range(0, 16)).map(|_| "*").collect::<String>(),
311        }
312    }
313}
314
315/// Enables to string and format for PointerLevelC types.
316impl fmt::Display for PointerLevelC {
317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318        write!(f, "{}", self.def)
319    }
320}
321
322/// A qucickcheck trait for describing how ArrayDimensionC types can be
323/// randomly generated and shrunk.
324impl Arbitrary for ArrayDimensionC {
325    fn arbitrary<G: Gen>(g: &mut G) -> ArrayDimensionC {
326        // Keep these small, clang complains when they get too big.
327        let dimensions = g.gen_range(0, 5);
328        let mut def = String::new();
329
330        let lower_bound = i32::from(cfg!(feature = "zero-sized-arrays"));
331
332        for _ in 1..dimensions {
333            // 16 is an arbitrary "not too big" number for capping array size.
334            def += &format!("[{}]", g.gen_range(lower_bound, 16));
335        }
336        ArrayDimensionC { def }
337    }
338}
339
340/// Enables to string and format for ArrayDimensionC types.
341impl fmt::Display for ArrayDimensionC {
342    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343        write!(f, "{}", self.def)
344    }
345}
346
347/// MakeUnique is used in generation of C headers to make BasicTypeDeclarationC
348/// identifiers unique.
349impl MakeUnique for BasicTypeDeclarationC {
350    fn make_unique(&mut self, stamp: usize) {
351        self.ident_id += &format!("_{}", stamp);
352    }
353}
354
355/// A qucickcheck trait for describing how BasicTypeDeclarationC types can be
356/// randomly generated and shrunk.
357impl Arbitrary for BasicTypeDeclarationC {
358    fn arbitrary<G: Gen>(g: &mut G) -> BasicTypeDeclarationC {
359        BasicTypeDeclarationC {
360            type_qualifier: Arbitrary::arbitrary(g),
361            type_name: Arbitrary::arbitrary(g),
362            pointer_level: Arbitrary::arbitrary(g),
363            array_dimension: Arbitrary::arbitrary(g),
364            ident_id: format!("{}", usize::arbitrary(g)),
365        }
366    }
367}
368
369/// Enables to string and format for BasicTypeDeclarationC types.
370impl fmt::Display for BasicTypeDeclarationC {
371    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372        write!(
373            f,
374            "{} {} {} ident_{}{};",
375            self.type_qualifier,
376            self.type_name,
377            self.pointer_level,
378            self.ident_id,
379            self.array_dimension
380        )
381    }
382}
383
384/// MakeUnique is used in generation of C headers to make StructDeclarationC
385/// identifiers unique.
386impl MakeUnique for StructDeclarationC {
387    fn make_unique(&mut self, stamp: usize) {
388        self.ident_id += &format!("_{}", stamp);
389    }
390}
391
392/// A qucickcheck trait for describing how StructDeclarationC types can be
393/// randomly generated and shrunk.
394impl Arbitrary for StructDeclarationC {
395    fn arbitrary<G: Gen>(g: &mut G) -> StructDeclarationC {
396        // Reduce generator size as a method of putting a bound on recursion.
397        // When size < 1 the empty list is generated.
398        let reduced_size: usize = (g.size() / 2) + 1;
399        let mut decl_list: DeclarationListC =
400            Arbitrary::arbitrary(&mut StdGen::new(thread_rng(), reduced_size));
401        let mut fields: DeclarationListC = DeclarationListC { decls: vec![] };
402
403        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
404            match *decl {
405                DeclarationC::FunctionDecl(_) => {}
406                ref mut decl => {
407                    decl.make_unique(i);
408                    fields.decls.push(decl.clone());
409                }
410            }
411        }
412
413        StructDeclarationC {
414            fields,
415            ident_id: format!("{}", usize::arbitrary(g)),
416            array_dimension: Arbitrary::arbitrary(g),
417        }
418    }
419}
420
421/// Enables to string and format for StructDeclarationC types.
422impl fmt::Display for StructDeclarationC {
423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424        write!(
425            f,
426            "struct {{ {} }} struct_{}{};",
427            self.fields, self.ident_id, self.array_dimension
428        )
429    }
430}
431
432/// MakeUnique is used in generation of C headers to make UnionDeclarationC
433/// identifiers unique.
434impl MakeUnique for UnionDeclarationC {
435    fn make_unique(&mut self, stamp: usize) {
436        self.ident_id += &format!("_{}", stamp);
437    }
438}
439
440/// A qucickcheck trait for describing how UnionDeclarationC types can be
441/// randomly generated and shrunk.
442impl Arbitrary for UnionDeclarationC {
443    fn arbitrary<G: Gen>(g: &mut G) -> UnionDeclarationC {
444        // Reduce generator size as a method of putting a bound on recursion.
445        // When size < 1 the empty list is generated.
446        let reduced_size: usize = (g.size() / 2) + 1;
447        let mut decl_list: DeclarationListC =
448            Arbitrary::arbitrary(&mut StdGen::new(thread_rng(), reduced_size));
449        let mut fields: DeclarationListC = DeclarationListC { decls: vec![] };
450
451        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
452            match *decl {
453                DeclarationC::FunctionDecl(_) => {}
454                ref mut decl => {
455                    decl.make_unique(i);
456                    fields.decls.push(decl.clone());
457                }
458            }
459        }
460
461        UnionDeclarationC {
462            fields,
463            ident_id: format!("{}", usize::arbitrary(g)),
464            array_dimension: Arbitrary::arbitrary(g),
465        }
466    }
467}
468
469/// Enables to string and format for UnionDeclarationC types.
470impl fmt::Display for UnionDeclarationC {
471    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472        write!(
473            f,
474            "union {{ {} }} union_{}{};",
475            self.fields, self.ident_id, self.array_dimension
476        )
477    }
478}
479
480/// MakeUnique is used in generation of C headers to make
481/// FunctionPointerDeclarationC identifiers unique.
482impl MakeUnique for FunctionPointerDeclarationC {
483    fn make_unique(&mut self, stamp: usize) {
484        self.ident_id += &format!("_{}", stamp);
485    }
486}
487
488/// A qucickcheck trait for describing how FunctionPointerDeclarationC types can
489/// be randomly generated and shrunk.
490impl Arbitrary for FunctionPointerDeclarationC {
491    fn arbitrary<G: Gen>(g: &mut G) -> FunctionPointerDeclarationC {
492        FunctionPointerDeclarationC {
493            type_qualifier: Arbitrary::arbitrary(g),
494            type_name: Arbitrary::arbitrary(g),
495            pointer_level: Arbitrary::arbitrary(g),
496            params: Arbitrary::arbitrary(g),
497            ident_id: format!("{}", usize::arbitrary(g)),
498        }
499    }
500}
501
502/// Enables to string and format for FunctionPointerDeclarationC types.
503impl fmt::Display for FunctionPointerDeclarationC {
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        write!(
506            f,
507            "{} {} {} (*func_ptr_{})({});",
508            self.type_qualifier,
509            self.type_name,
510            self.pointer_level,
511            self.ident_id,
512            self.params
513        )
514    }
515}
516
517/// MakeUnique is used in generation of C headers to make FunctionPrototypeC
518/// identifiers unique.
519impl MakeUnique for FunctionPrototypeC {
520    fn make_unique(&mut self, stamp: usize) {
521        self.ident_id += &format!("_{}", stamp);
522    }
523}
524
525/// A qucickcheck trait for describing how FunctionPrototypeC types can be
526/// randomly generated and shrunk.
527impl Arbitrary for FunctionPrototypeC {
528    fn arbitrary<G: Gen>(g: &mut G) -> FunctionPrototypeC {
529        FunctionPrototypeC {
530            type_qualifier: Arbitrary::arbitrary(g),
531            type_name: Arbitrary::arbitrary(g),
532            pointer_level: Arbitrary::arbitrary(g),
533            params: Arbitrary::arbitrary(g),
534            ident_id: format!("{}", usize::arbitrary(g)),
535        }
536    }
537}
538
539/// Enables to string and format for FunctionPrototypeC types.
540impl fmt::Display for FunctionPrototypeC {
541    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542        write!(
543            f,
544            "{} {} {} func_{}({});",
545            self.type_qualifier,
546            self.type_name,
547            self.pointer_level,
548            self.ident_id,
549            self.params
550        )
551    }
552}
553
554/// A qucickcheck trait for describing how ParameterC types can be
555/// randomly generated and shrunk.
556impl Arbitrary for ParameterC {
557    fn arbitrary<G: Gen>(g: &mut G) -> ParameterC {
558        ParameterC {
559            type_qualifier: Arbitrary::arbitrary(g),
560            type_name: Arbitrary::arbitrary(g),
561            pointer_level: Arbitrary::arbitrary(g),
562        }
563    }
564}
565
566/// Enables to string and format for ParameterC types.
567impl fmt::Display for ParameterC {
568    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569        write!(
570            f,
571            "{} {} {}",
572            self.type_qualifier, self.type_name, self.pointer_level
573        )
574    }
575}
576
577/// A qucickcheck trait for describing how ParameterListC types can be
578/// randomly generated and shrunk.
579impl Arbitrary for ParameterListC {
580    fn arbitrary<G: Gen>(g: &mut G) -> ParameterListC {
581        ParameterListC {
582            params: Arbitrary::arbitrary(g),
583        }
584    }
585}
586
587/// Enables to string and format for ParameterListC types.
588impl fmt::Display for ParameterListC {
589    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590        let mut display = String::new();
591        for (i, p) in self.params.iter().enumerate() {
592            match i {
593                0 => display += &format!("{}", p),
594                _ => display += &format!(",{}", p),
595            }
596        }
597        write!(f, "{}", display)
598    }
599}
600
601/// A qucickcheck trait for describing how HeaderC types can be
602/// randomly generated and shrunk.
603impl Arbitrary for HeaderC {
604    fn arbitrary<G: Gen>(g: &mut G) -> HeaderC {
605        let mut decl_list: DeclarationListC = Arbitrary::arbitrary(g);
606        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
607            decl.make_unique(i);
608        }
609        HeaderC { def: decl_list }
610    }
611}
612
613/// Enables to string and format for HeaderC types.
614impl fmt::Display for HeaderC {
615    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616        let mut display = String::new();
617        for decl in &self.def.decls {
618            display += &format!("{}", decl);
619        }
620        write!(f, "{}", display)
621    }
622}
623
624/// Use Display trait for Debug so that any failing property tests report
625/// generated C code rather than the data structures that contain it.
626impl fmt::Debug for HeaderC {
627    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
628        write!(f, "{}", self)
629    }
630}
631