Syntax & Data Types
Relevant source files
The following files were used as context for generating this wiki page:
Crucible defines a unified type system that maps core data structures and primitive types across multiple programming languages. The system ensures type safety and consistent behavior for API operations, regardless of the target client language. The core engine lowers these types from the Crucible Intermediate Representation (IR) into language-specific syntax.
Core Data Types
The system categorizes data into simple kinds, collections, and complex structures. Simple kinds represent basic scalar values, while complex structures allow for nested and recursive data modeling.
Simple Kinds Mapping
The following table details how Crucible's simple kinds map to native types in different supported languages.
| Simple Kind | TypeScript | Go | C# | Dart | Kotlin |
|---|---|---|---|---|---|
| String | string | string | string | String | String |
| Boolean | boolean | bool | bool | bool | Boolean |
| Integer | number | int32 | int | int | Int |
| Long | bigint | int64 | long | BigInt | Long |
| Float | number | float32 | float | double | Float |
| Double | number | float64 | double | double | Double |
| BigInteger | bigint | *big.Int | BigInteger | BigInt | BigInteger |
| BigDecimal | Decimal | Decimal | BigDecimal | BigDecimal | BigDecimal |
| Timestamp | Date | time.Time | DateTimeOffset | Timestamp | Instant |
| Blob | Uint8Array | []byte | byte[] | Uint8List | ByteArray |
| Document | Document | any | JsonNode | JsonValue | JsonElement |
Sources: crates/crucible-codegen-ts/src/names.rs:20-33, crates/crucible-codegen-go/src/lib.rs:72-85, crates/crucible-codegen-csharp/src/lib.rs:90-105, crates/crucible-codegen-dart/src/snippet.rs:28-66, crates/crucible-codegen-kotlin/src/snippet.rs:136-160
Complex Types
Crucible supports higher-level structures for modeling complex API data.
- Structure: A named collection of members. In C#, these are generated as
sealed classwith object initializers. In Go, they are represented asstruct. - Union: A type that carries exactly one of its members at a time. Go represents these as pointers within a struct, while C# uses a specialized class with an
UnknownVariantproperty. - Enum: A set of named string constants. Crucible enums are "open," meaning they preserve unrecognized values from the wire.
- IntEnum: A set of named integer constants, similarly preserving unrecognized values.
- List/Map: Collections of types. The system handles recursive collections (e.g., a List containing itself) by using nominal classes to break cycles.
Sources: crates/crucible-codegen-csharp/src/lib.rs:434-526, crates/crucible-codegen-go/src/lib.rs:253-294, crates/crucible-codegen-kotlin/src/snippet.rs:100-112
Type Transformation Logic
The codegen engines use a multi-step transformation to convert IR shapes into target language identifiers.
This diagram shows the transformation flow from Crucible IR shapes to language-specific implementations.
Naming Conventions
Each generator applies specific casing rules and escapes keywords to ensure valid source code.
- PascalCase: Used for type names in C#, Go, and Kotlin.
- snake_case: Used for field names in Rust and Go (internal representation).
- camelCase: Used for method names in TypeScript and Dart.
- Keyword Escaping: Reserved words (like
class,type,self) are escaped using prefixes like@(C#) orr#(Rust/Go) or by adding a suffix like_.
Sources: crates/crucible-codegen-ts/src/names.rs:64-77, crates/crucible-codegen-go/src/lib.rs:55-68, crates/crucible-codegen-csharp/src/lib.rs:36-62, crates/crucible-codegen-rust/src/names.rs:12-46
Nullability and Presence
Crucible distinguishes between absent members, explicit nulls, and values with defaults.
Presence Handling in C#
In C#, members that can be absent use an Optional<T> wrapper. A property named {FieldName}Presence tracks whether the field was set by the caller. If a member has a default value defined in the model, the runtime fills it when the member is omitted.
Presence Handling in Go
Go utilizes pointers for sparse collections and an Optional[T] type for members that may be absent. This allows the client to distinguish between a zero-value and an unset value.
Sources: crates/crucible-codegen-csharp/src/lib.rs:408-418, crates/crucible-codegen-go/src/lib.rs:114-124, crates/crucible-codegen-ts/src/names.rs:38-46
Recursive Data Structures
The system allows for recursive definitions, such as a Node structure containing a list of Node children. To prevent infinite recursion during type generation, specifically in languages like C# and Kotlin, the generator identifies cycles and uses nominal types (named classes) to break the cycle.
The diagram illustrates a nominal list type breaking a recursion cycle between a structure and a collection.
Sources: crates/crucible-codegen-csharp/src/lib.rs:569-580, crates/crucible-codegen-kotlin/src/snippet.rs:84-97
Summary
Crucible's syntax and data types provide a robust foundation for cross-language API development. By mapping IR shapes to native primitives and handling complex behaviors like nullability and recursion, the project ensures that API contracts are strictly enforced across TypeScript, Go, C#, Dart, and Kotlin clients. Crucially, the system maintains "open" enums and specific numeric precision (like BigDecimal) to ensure wire-level compatibility across all platforms.