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