jam.types.base.choices
Choice type implementations for the JAM protocol.
Type Definitions
Choice[T]
Tagged union type
Discriminant + value encoding
Type-safe variant selection
Compile-time variant checking
Option[T]
Nullable type wrapper
Special case of Choice
None or Some(T)
Zero overhead for None
Encoding Format
Choice[T]
Tagged union format:
[Tag: varint][Value: varies]
Tag: Index of the variant (0-based)
Value: Encoded variant value
Option[T]
Special encoding:
None -> [00] # Single byte
Some(value) -> [01][Encoded value]
Implementation Details
Memory Layout
Tag: Variable size integer
Value: Variable size
No padding between tag and value
Alignment preserved for value
Type Safety
Variant types checked at compile time
Runtime type validation
Tag range validation
Value type checking
Error Handling
Common error cases:
Invalid variant:
if tag >= len(variants): raise ValueError(f"Invalid variant tag: {tag}")
Type mismatch:
if not isinstance(value, variant_type): raise TypeError(f"Expected {variant_type}, got {type(value)}")
Buffer overflow:
if len(buffer) - offset < tag_size: raise BufferError(f"Buffer too small for tag")
Examples
Choice Type
from dataclasses import dataclass
from jam.types.base.choices import Choice, decodable_choice
from jam.types.base.integers import U32
from jam.types.base.string import String
# Define variants
@dataclass
class Number:
value: U32
@dataclass
class Text:
value: String
# Create choice type
@decodable_choice(Number, Text)
class Value:
variant: Choice[Number, Text]
# Create and encode number variant
num = Value(Number(U32(42)))
encoded = num.encode() # -> [00 2A 00 00 00]
# Create and encode text variant
text = Value(Text(String("hello")))
encoded = text.encode() # -> [01 05 68 65 6C 6C 6F]
Option Type
from jam.types.base.choices import Option, decodable_option
from jam.types.base.integers import U32
# Define optional type
@decodable_option(U32)
class OptionalNumber:
value: Option[U32]
# None case
none = OptionalNumber(None)
encoded = none.encode() # -> [00]
# Some case
some = OptionalNumber(U32(42))
encoded = some.encode() # -> [01 2A 00 00 00]
# Decode
decoded = OptionalNumber.decode(encoded)
assert decoded.value == U32(42)
API Reference
Classes
- class jam.types.base.choices.Choice(initial: Dict[str, Codable[T]] | Codable[T])[source]
Bases:
Codable[T],JsonSerde,Generic[T]A choice is a value that can be one of several possible types.
A Choice represents a tagged union type that can hold a value of one of several possible Codable types. The actual type is determined by a tag byte during encoding/decoding.
- To use a choice, you need to define all possible types:
>>> @decodable_choice([U8, U16]) >>> class MyChoice(Choice): ... >>> my_choice: MyChoice = MyChoice(U8(1)) >>> assert my_choice.type == U8 >>> assert my_choice.value == U8(1)
- To use a optional choice, we’d pair it with Nullable:
>>> @decodable_choice([U8, Nullable]) >>> class OptionalU8(Choice): ... >>> my_choice: OptionalU8 = OptionalU8(U8(1)) >>> assert my_choice.type == U8 >>> assert my_choice.value == U8(1) >>> my_choice: OptionalU8 = OptionalU8(Null) >>> assert my_choice.type == Nullable >>> assert my_choice.value is None
- To use this as an enum:
>>> @decodable_choice([String, String, String]) >>> class OutputType(Choice): ...
- __init__(initial: Dict[str, Codable[T]] | Codable[T])[source]
Initialize Choice.
- Parameters:
initial – Mapping of initial choice name and its value. Should have only one key.
- Raises:
ValueError – If types list is empty
- __set_internal__(value: Dict[str, Codable[T]] | Codable[T]) None[source]
Set the choice value.
- Parameters:
value – Value to set. Must be instance of one of the allowed types.
- Raises:
ValueError – If value type is not in allowed types list
- class jam.types.base.choices.Option(initial: Codable = Null)[source]
Bases:
ChoiceAn option is a choice that can be either None or a value.
- __init__(initial: Codable = Null)[source]
Initialize Choice.
- Parameters:
initial – Mapping of initial choice name and its value. Should have only one key.
- Raises:
ValueError – If types list is empty