tsrkit-types


Nametsrkit-types JSON
Version 0.1.8 PyPI version JSON
download
home_pageNone
SummaryPerformant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies
upload_time2025-07-11 06:47:43
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseNone
keywords serialization binary encoding types codable json validation data-types type-safety zero-copy protocol struct networking performance bytes integers strings
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # TSRKit Types

Performant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies.

Perfect for network protocols, game state serialization, configuration files, and any application requiring efficient, validated data handling.

## Features

- **🔒 Type Safe**: Strong typing with runtime validation and type hints
- **âš¡ High Performance**: Efficient binary encoding with zero-copy operations where possible  
- **📦 Zero Dependencies**: No external runtime dependencies
- **🔄 Dual Serialization**: Both binary and JSON serialization support
- **🧩 Generic Support**: Parameterized types for flexible, reusable code
- **🎯 Memory Efficient**: Minimal overhead, extends built-in Python types
- **🚀 Easy to Use**: Intuitive API with comprehensive type system

## Installation

```bash
pip install tsrkit-types
```

## Type Categories

### Integer Types (extension of Python int)

#### Unsigned Integers (`Uint`)

The `Uint` class provides both fixed-size and variable-size unsigned integers.

**Fixed-Size Integers:**
```python
from tsrkit_types.integers import Uint

# Pre-defined types
value = Uint[8](255)        # 8-bit unsigned integer (0-255)
value = Uint[16](65535)     # 16-bit unsigned integer (0-65535) 
value = Uint[32](42949)     # 32-bit unsigned integer
value = Uint[64](1844674)   # 64-bit unsigned integer

# Dynamic size specification
U128 = Uint[128]       # 128-bit unsigned integer
value = U128(123456789)

# Encoding/Decoding
encoded = value.encode()           # Encode to bytes
decoded = U8.decode(encoded)       # Decode from bytes
size = value.encode_size()         # Get encoded size
```

**Variable-Size General Integers:**
```python
# General integers (supports up to 2^64 - 1 with variable encoding)
num = Uint(1000)       # Variable-length encoding
encoded = num.encode()
decoded = Uint.decode(encoded)

# Arithmetic operations preserve type
a = Uint[8](10)
b = Uint[8](20)
result = a + b         # result is Uint[8](30)
```

**Encoding Details:**
- Fixed-size integers use little-endian encoding
- Variable-size integers use a compact encoding scheme that optimizes for smaller values
- Values < 2^7 are encoded in 1 byte
- Larger values use a variable-length prefix encoding

### String Types (extension of Python str)

#### UTF-8 Strings (`String`)

```python
from tsrkit_types.string import String

# Creation
text = String("Hello, World!")
text = String("Unicode: 🚀🔥")

# Properties
length = len(text)               # Character count
text_str = str(text)            # Convert to Python str

# Encoding/Decoding
encoded = text.encode()          # [length][utf8_bytes]
decoded = String.decode(encoded)

# JSON serialization
json_data = text.to_json()       # Returns the string value
restored = String.from_json(json_data)
```

**Encoding Format:**
- Length prefix (variable-length `Uint`) followed by UTF-8 bytes
- String length is measured in UTF-16 code units (like Python strings)

### Boolean Types

#### Boolean (`Bool`)

```python
from tsrkit_types.bool import Bool

# Creation
true_val = Bool(True)
false_val = Bool(False)

# Usage
if true_val:                     # Supports truthiness testing
    print("It's true!")

# Encoding/Decoding
encoded = true_val.encode()      # 1 byte: 0x01 or 0x00
decoded = Bool.decode(encoded)

# JSON serialization
json_str = true_val.to_json()    # "true" or "false"
restored = Bool.from_json("true")
```

### Null Types

```python
from tsrkit_types.null import Null

# Null type
null_val = Null                  # Singleton null value
```

### Choice and Option Types

#### Choice (Union Types)

```python
from tsrkit_types.choice import Choice
from tsrkit_types.integers import U8, U16
from tsrkit_types.string import String

# Anonymous choice
IntOrString = Choice[U8, String]
value = IntOrString(U8(42))
value = IntOrString(String("hello"))

# Switch the choice
value.set(String("world"))
inner = value.unwrap()           # Get the inner value

# Named choice with custom keys
class Result(Choice):
    success: String
    error: U8

result = Result(String("OK"))
result = Result(U8(404), key="error")

# JSON serialization
json_data = result.to_json()     # {"success": "OK"} or {"error": 404}
restored = Result.from_json(json_data)

# Encoding
encoded = result.encode()        # [variant_index][value]
decoded = Result.decode(encoded)
```

#### Option (Optional Value - T | Null)

```python
from tsrkit_types.option import Option
from tsrkit_types.integers import U32

# Optional value
opt_val = Option[U32](U32(100))  # Some value
empty_opt = Option[U32]()        # None/Null

# Check if has value
if opt_val:                      # Truthiness test
    value = opt_val.unwrap()     # Get the U32 value

# Encoding (more efficient than general Choice)
encoded = opt_val.encode()       # 1 byte tag + optional value
decoded = Option[U32].decode(encoded)
```

### Container Types

#### Sequences (Extension of Python list)

```python
from tsrkit_types.sequences import Array, Vector, TypedArray, TypedVector
from tsrkit_types.integers import U16

# Fixed-size array
FixedArray = Array[10]           # Array of exactly 10 elements
arr = FixedArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

# Typed fixed-size array  
TypedFixedArray = TypedArray[U16, 5]  # 5 U16 elements
typed_arr = TypedFixedArray([U16(1), U16(2), U16(3), U16(4), U16(5)])

# Variable-size vector
DynamicVector = Vector[100]       # Vector with max 100 elements
vec = DynamicVector([1, 2, 3])

# Typed variable-size vector
TypedDynamicVector = TypedVector[U16]  # Vector of U16 elements
typed_vec = TypedDynamicVector([U16(1), U16(2)])

# Operations
vec.append(4)                    # Add element with validation
vec.extend([5, 6, 7])           # Add multiple elements
vec[0] = 100                    # Set element with validation

# Encoding
encoded = typed_vec.encode()     # [length?][element1][element2]...
decoded = TypedDynamicVector.decode(encoded)
```

**Sequence Types:**
- `Array[N]`: Fixed size, any element type
- `Vector`: Variable size, any element type  
- `TypedArray[T, N]`: Fixed size with typed elements
- `TypedVector[T]`: Variable size with typed elements
- `BoundedVector[min, max]`: Size constrained vector
- `TypedBoundedVector[T, min, max]`: Typed and size constrained

#### Dictionary

```python
from tsrkit_types.dictionary import Dictionary
from tsrkit_types.string import String
from tsrkit_types.integers import U32

# Create dictionary type
StringToInt = Dictionary[String, U32]
data = StringToInt({
    String("key1"): U32(100),
    String("key2"): U32(200)
})

# Operations
data[String("key3")] = U32(300)   # Add entry
value = data[String("key1")]      # Get value
del data[String("key2")]          # Remove entry

# Iteration
for key, value in data.items():
    print(f"{key}: {value}")

# Encoding
encoded = data.encode()           # [length][key1][value1][key2][value2]...
decoded = StringToInt.decode(encoded)

# JSON serialization
json_data = data.to_json()        # {"key1": 100, "key3": 300}
restored = StringToInt.from_json(json_data)
```

### Bytes Types

The library provides two complementary byte array types: immutable `Bytes` (extending Python's built-in `bytes`) and mutable `ByteArray` (extending Python's `bytearray`). Both types share common functionality through a mixin architecture for bit conversion, JSON serialization, and binary encoding.

#### Bytes (Immutable - extension of Python bytes)

```python
from tsrkit_types.bytes import Bytes

# Creation
data = Bytes(b"Hello, binary world!")
data = Bytes([0x01, 0x02, 0x03, 0x04])
data = Bytes("48656c6c6f")        # From hex string

# Shared Operations (via BytesMixin)
bits = data.to_bits()            # Convert to bit list [True, False, True, ...]
data2 = Bytes.from_bits(bits)    # Create from bit list

# Properties
length = len(data)               # Byte length
raw_bytes = bytes(data)         # Convert to Python bytes

# Encoding/Decoding
encoded = data.encode()          # [length][raw_bytes]
decoded = Bytes.decode(encoded)

# JSON serialization (hex encoded)
json_str = data.to_json()        # "48656c6c6f2c2062696e61727920776f726c6421"
restored = Bytes.from_json(json_str)
restored2 = Bytes.from_json("0x48656c6c6f")  # Supports 0x prefix
```

#### ByteArray (Mutable - extension of Python bytearray)

```python
from tsrkit_types.bytearray import ByteArray

# Creation
data = ByteArray(b"Hello, binary world!")
data = ByteArray([0x01, 0x02, 0x03, 0x04])
data = ByteArray("48656c6c6f")   # From hex string

# Mutable Operations
data.append(0xFF)                # Add single byte
data.extend([0xAB, 0xCD])       # Add multiple bytes
data.insert(0, 0x00)            # Insert byte at position
data.pop()                      # Remove and return last byte
data.remove(0xFF)               # Remove first occurrence
data.clear()                    # Remove all bytes
data.reverse()                  # Reverse in-place

# Indexing and Slicing (mutable)
data[0] = 0x42                  # Set byte at index
data[1:3] = [0x43, 0x44]       # Set slice
del data[0]                     # Delete byte at index

# Shared Operations (via BytesMixin) - same as Bytes
bits = data.to_bits()           # Convert to bit list
data2 = ByteArray.from_bits(bits)  # Create from bit list

# Properties and Conversion
length = len(data)              # Byte length  
raw_bytes = bytes(data)         # Convert to immutable bytes
immutable = Bytes(data)         # Convert to immutable Bytes

# Encoding/Decoding (same interface as Bytes)
encoded = data.encode()         # [length][raw_bytes]
decoded = ByteArray.decode(encoded)

# JSON serialization (same interface as Bytes)
json_str = data.to_json()       # "48656c6c6f..."
restored = ByteArray.from_json(json_str)
```

**Key Differences:**
- **Bytes**: Immutable, extends `bytes`, memory-efficient for read-only data
- **ByteArray**: Mutable, extends `bytearray`, suitable for dynamic byte manipulation
- **Shared Functionality**: Both support identical bit conversion, JSON serialization, and binary encoding through `BytesMixin`

**Common Features (Both Types):**
- Bit-level conversion with MSB/LSB support
- Hex string JSON serialization with 0x prefix support
- Efficient binary encoding with length prefix
- String representation and validation
- Memory-efficient operations

#### Bits (Bit Arrays - Sequence of bool)

```python
from tsrkit_types.bits import Bits

# Creation
bits = Bits([True, False, True, True, False])
bits = Bits.from_hex("1A3F")       # From hex string
bits = Bits.from_int(42, 8)        # From integer with bit width

# Fixed-size parameterized bits
FixedBits = Bits[8]                # Exactly 8 bits
fixed = FixedBits([True, False, True, True, False, False, True, False])

# Operations
bit_val = bits[0]                  # Get bit at index
bits[1] = True                     # Set bit at index
bits.append(False)                 # Add bit
bits.extend([True, False])         # Add multiple bits

# Conversion
hex_str = bits.to_hex()            # Convert to hex string
int_val = bits.to_int()            # Convert to integer

# Bit order specification
bits_msb = Bits([True, False], bit_order="MSB")  # Most significant bit first
bits_lsb = Bits([True, False], bit_order="LSB")  # Least significant bit first

# Encoding
encoded = bits.encode()            # [length][packed_bits]
decoded = Bits.decode(encoded)

# JSON serialization
json_str = bits.to_json()          # Hex string representation
restored = Bits.from_json(json_str)
```

### Enum (Extension of Python Enum, with Codable + JSON support)

```python
from tsrkit_types.enum import Enum

# Define enum
class Color(Enum):
    RED = 0
    GREEN = 1
    BLUE = 2

# Usage
color = Color.RED
color_val = Color(1)             # Color.GREEN

# String conversion
name = color.name                # "RED"
value = color.value              # 0

# Encoding
encoded = color.encode()         # Variable-length uint encoding
decoded = Color.decode(encoded)

# JSON serialization
json_data = color.to_json()      # "RED"
restored = Color.from_json("GREEN")
```

### Structured Types

#### Struct Decorator (Extension of dataclasses)

```python
from tsrkit_types.struct import struct
from tsrkit_types.string import String
from tsrkit_types.integers import U8, U32
from dataclasses import field

@structure
class Person:
    name: String
    age: U8
    
@structure  
class Employee:
    person: Person
    employee_id: U32
    department: String = field(metadata={"default": String("Unknown")})

# Creation
person = Person(name=String("John Doe"), age=U8(30))
employee = Employee(
    person=person,
    employee_id=U32(12345),
    department=String("Engineering")
)

# Access fields
print(employee.person.name)      # "John Doe"
print(employee.employee_id)      # 12345

# Encoding/Decoding
encoded = employee.encode()      # Concatenated field encodings
decoded = Employee.decode(encoded)

# JSON serialization with custom field names
@structure
class CustomPerson:
    name: String = field(metadata={"name": "full_name"})
    age: U8

person = CustomPerson(name=String("Jane"), age=U8(25))
json_data = person.to_json()     # {"full_name": "Jane", "age": 25}
restored = CustomPerson.from_json({"full_name": "Jane", "age": 25})
```

**Struct Features:**
- Automatic `Codable` implementation
- Field validation and type checking
- Default values via metadata
- Custom JSON field mapping
- Inheritance support
- Frozen/immutable variants

## Advanced Usage

### Custom Types

Implement your own `Codable` types:

```python
from tsrkit_types.itf.codable import Codable
from typing import Tuple, Union

class Point3D(Codable):
    def __init__(self, x: float, y: float, z: float):
        self.x, self.y, self.z = x, y, z
    
    def encode_size(self) -> int:
        return 24  # 3 doubles = 24 bytes
    
    def encode_into(self, buffer: bytearray, offset: int = 0) -> int:
        import struct
        struct.pack_into('<ddd', buffer, offset, self.x, self.y, self.z)
        return 24
    
    @classmethod
    def decode_from(cls, buffer: Union[bytes, bytearray, memoryview], 
                   offset: int = 0) -> Tuple['Point3D', int]:
        import struct
        x, y, z = struct.unpack_from('<ddd', buffer, offset)
        return cls(x, y, z), 24
```

### Configuration and Optimization

```python
# Optimize for specific use cases
@structure(frozen=True)             # Immutable structs
class ImmutableData:
    value: U64

# Memory-efficient sequences
CompactArray = TypedArray[U8, 1000]  # 1000 bytes exactly
data = CompactArray([0] * 1000)

# Bounded containers for validation
BoundedList = BoundedVector[10, 100]  # Between 10 and 100 elements
safe_list = BoundedList([0] * 50)
```

### Error Handling

```python
from tsrkit_types.integers import U8

try:
    # Value out of range
    invalid = U8(256)               # Raises ValueError
except ValueError as e:
    print(f"Range error: {e}")

try:
    # Type mismatch in Choice
    choice = Choice[U8, String](42) # Raises TypeError
except TypeError as e:
    print(f"Type error: {e}")

try:
    # Buffer too small for decoding
    corrupted = b"\x01"
    U32.decode(corrupted)           # Raises ValueError
except ValueError as e:
    print(f"Decode error: {e}")
```


## Core Interface

All types implement the `Codable` interface:

```python
from tsrkit_types.itf.codable import Codable

class MyType(Codable):
    def encode_size(self) -> int: ...      # Size needed for encoding
    def encode_into(self, buffer: bytearray, offset: int = 0) -> int: ...  # Encode into buffer
    def encode(self) -> bytes: ...         # Encode to new bytes object
    
    @classmethod
    def decode_from(cls, buffer: bytes, offset: int = 0) -> Tuple[T, int]: ...  # Decode from buffer
    @classmethod
    def decode(cls, buffer: bytes, offset: int = 0) -> T: ...  # Decode from buffer (convenience)
```

## Performance Considerations

### Encoding Efficiency

- **Fixed-size types** (U8, U16, etc.) have constant encoding size
- **Variable-size types** (general Uint) optimize for smaller values
- **Sequences** encode length only when necessary (variable-size)
- **Strings** use UTF-8 encoding with variable-length prefix

### Memory Usage

- Types extend built-in Python types where possible (int, str, list, dict)
- Zero-copy operations where feasible
- Minimal overhead for type metadata

### Best Practices

```python
# Prefer fixed-size types when range is known
user_id = U32(123456)            # Better than Uint(123456)

# Use typed containers for homogeneous data
scores = TypedVector[U16]([100, 95, 87, 92])

# Batch operations for better performance
data = TypedArray[U8, 1000]([0] * 1000)
encoded = data.encode()          # Single operation vs. encoding each element

# Reuse buffer for multiple encodings
buffer = bytearray(1024)
offset = 0
offset += value1.encode_into(buffer, offset)
offset += value2.encode_into(buffer, offset)

# Choose appropriate byte type for your use case
# Use Bytes for immutable binary data (memory efficient, read-only)
config_data = Bytes(b"static configuration")

# Use ByteArray for dynamic binary buffers (mutable, growing data)
dynamic_buffer = ByteArray()
dynamic_buffer.extend([0x01, 0x02])
dynamic_buffer.append(0x03)
dynamic_buffer.insert(0, 0x00)  # Result: [0x00, 0x01, 0x02, 0x03]
```

## Examples

### Network Protocol

```**python**
@structure
class NetworkPacket:
    packet_type: U8
    session_id: U32
    payload_length: U16
    payload: Bytes

# Create packet
packet = NetworkPacket(
    packet_type=U8(1),
    session_id=U32(0x12345678),
    payload_length=U16(13),
    payload=Bytes(b"Hello, World!")
)

# Serialize for transmission
wire_data = packet.encode()

# Deserialize on receiver
received_packet = NetworkPacket.decode(wire_data)
```

### Configuration File

```python
@structure
class DatabaseConfig:
    host: String
    port: U16
    username: String 
    password: String
    max_connections: U8 = field(metadata={"default": U8(10)})
    ssl_enabled: Bool = field(metadata={"default": Bool(True)})

# Create config
config = DatabaseConfig(
    host=String("localhost"),
    port=U16(5432),
    username=String("admin"),
    password=String("secret")
)

# Save to JSON
import json
with open("db_config.json", "w") as f:
    json.dump(config.to_json(), f)

# Load from JSON
with open("db_config.json", "r") as f:
    data = json.load(f)
    config = DatabaseConfig.from_json(data)
```

### Game State Serialization

```python
class GameEntityType(Enum):
    PLAYER = 0
    ENEMY = 1
    ITEM = 2

@structure
class Position:
    x: U16
    y: U16

@structure  
class GameEntity:
    entity_type: GameEntityType
    position: Position
    health: U8
    name: String

@structure
class GameState:
    level: U8
    score: U32
    entities: TypedVector[GameEntity]

# Create game state
state = GameState(
    level=U8(1),
    score=U32(1500),
    entities=TypedVector[GameEntity]([
        GameEntity(
            entity_type=GameEntityType.PLAYER,
            position=Position(x=U16(100), y=U16(200)),
            health=U8(100),
            name=String("Hero")
        )
    ])
)

# Save/load game
save_data = state.encode()
loaded_state = GameState.decode(save_data)
```

## Development

### Setup

1. **Clone the repository:**
   ```bash
   git clone https://github.com/chainscore/tsrkit-types.git
   cd tsrkit-types
   ```

2. **Install development dependencies:**
   ```bash
   pip install -e ".[dev]"
   ```

### Running Tests

**Run the full test suite:**
```bash
pytest
```

**Run tests with coverage:**
```bash
pytest --cov=tsrkit_types --cov-report=html
```

**Run tests in parallel (faster):**
```bash
pytest -n auto
```

**Run specific test categories:**
```bash
pytest tests/test_integers.py      # Integer type tests
pytest tests/test_strings.py       # String type tests  
pytest tests/test_containers.py    # Container type tests
pytest tests/test_structs.py       # Struct tests
pytest tests/test_network.py       # Network protocol tests
```

**Run tests with verbose output:**
```bash
pytest -v
```

**Skip slow tests:**
```bash
pytest -m "not slow"
```

### Build and Publish

1. Build the package:

```bash
python3 -m build --wheel
```

2. Publish the wheels:

```bash
twine upload dist/*
```

### Test Coverage

View the test coverage report:
```bash
# Generate HTML coverage report
pytest --cov=tsrkit_types --cov-report=html
open htmlcov/index.html  # macOS
# or xdg-open htmlcov/index.html  # Linux
```

## License

MIT License - see [LICENSE](LICENSE) file for details.

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## Requirements

- **Python**: >= 3.11
- **Runtime Dependencies**: None (zero dependencies!)
- **Development Dependencies**: pytest and plugins (see `pyproject.toml`) 

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "tsrkit-types",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "serialization, binary, encoding, types, codable, json, validation, data-types, type-safety, zero-copy, protocol, struct, networking, performance, bytes, integers, strings",
    "author": null,
    "author_email": "chainscore-labs <hello@chainscore.finance>, prasad-kumkar <prasad@chainscore.finance>",
    "download_url": null,
    "platform": null,
    "description": "# TSRKit Types\n\nPerformant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies.\n\nPerfect for network protocols, game state serialization, configuration files, and any application requiring efficient, validated data handling.\n\n## Features\n\n- **\ud83d\udd12 Type Safe**: Strong typing with runtime validation and type hints\n- **\u26a1 High Performance**: Efficient binary encoding with zero-copy operations where possible  \n- **\ud83d\udce6 Zero Dependencies**: No external runtime dependencies\n- **\ud83d\udd04 Dual Serialization**: Both binary and JSON serialization support\n- **\ud83e\udde9 Generic Support**: Parameterized types for flexible, reusable code\n- **\ud83c\udfaf Memory Efficient**: Minimal overhead, extends built-in Python types\n- **\ud83d\ude80 Easy to Use**: Intuitive API with comprehensive type system\n\n## Installation\n\n```bash\npip install tsrkit-types\n```\n\n## Type Categories\n\n### Integer Types (extension of Python int)\n\n#### Unsigned Integers (`Uint`)\n\nThe `Uint` class provides both fixed-size and variable-size unsigned integers.\n\n**Fixed-Size Integers:**\n```python\nfrom tsrkit_types.integers import Uint\n\n# Pre-defined types\nvalue = Uint[8](255)        # 8-bit unsigned integer (0-255)\nvalue = Uint[16](65535)     # 16-bit unsigned integer (0-65535) \nvalue = Uint[32](42949)     # 32-bit unsigned integer\nvalue = Uint[64](1844674)   # 64-bit unsigned integer\n\n# Dynamic size specification\nU128 = Uint[128]       # 128-bit unsigned integer\nvalue = U128(123456789)\n\n# Encoding/Decoding\nencoded = value.encode()           # Encode to bytes\ndecoded = U8.decode(encoded)       # Decode from bytes\nsize = value.encode_size()         # Get encoded size\n```\n\n**Variable-Size General Integers:**\n```python\n# General integers (supports up to 2^64 - 1 with variable encoding)\nnum = Uint(1000)       # Variable-length encoding\nencoded = num.encode()\ndecoded = Uint.decode(encoded)\n\n# Arithmetic operations preserve type\na = Uint[8](10)\nb = Uint[8](20)\nresult = a + b         # result is Uint[8](30)\n```\n\n**Encoding Details:**\n- Fixed-size integers use little-endian encoding\n- Variable-size integers use a compact encoding scheme that optimizes for smaller values\n- Values < 2^7 are encoded in 1 byte\n- Larger values use a variable-length prefix encoding\n\n### String Types (extension of Python str)\n\n#### UTF-8 Strings (`String`)\n\n```python\nfrom tsrkit_types.string import String\n\n# Creation\ntext = String(\"Hello, World!\")\ntext = String(\"Unicode: \ud83d\ude80\ud83d\udd25\")\n\n# Properties\nlength = len(text)               # Character count\ntext_str = str(text)            # Convert to Python str\n\n# Encoding/Decoding\nencoded = text.encode()          # [length][utf8_bytes]\ndecoded = String.decode(encoded)\n\n# JSON serialization\njson_data = text.to_json()       # Returns the string value\nrestored = String.from_json(json_data)\n```\n\n**Encoding Format:**\n- Length prefix (variable-length `Uint`) followed by UTF-8 bytes\n- String length is measured in UTF-16 code units (like Python strings)\n\n### Boolean Types\n\n#### Boolean (`Bool`)\n\n```python\nfrom tsrkit_types.bool import Bool\n\n# Creation\ntrue_val = Bool(True)\nfalse_val = Bool(False)\n\n# Usage\nif true_val:                     # Supports truthiness testing\n    print(\"It's true!\")\n\n# Encoding/Decoding\nencoded = true_val.encode()      # 1 byte: 0x01 or 0x00\ndecoded = Bool.decode(encoded)\n\n# JSON serialization\njson_str = true_val.to_json()    # \"true\" or \"false\"\nrestored = Bool.from_json(\"true\")\n```\n\n### Null Types\n\n```python\nfrom tsrkit_types.null import Null\n\n# Null type\nnull_val = Null                  # Singleton null value\n```\n\n### Choice and Option Types\n\n#### Choice (Union Types)\n\n```python\nfrom tsrkit_types.choice import Choice\nfrom tsrkit_types.integers import U8, U16\nfrom tsrkit_types.string import String\n\n# Anonymous choice\nIntOrString = Choice[U8, String]\nvalue = IntOrString(U8(42))\nvalue = IntOrString(String(\"hello\"))\n\n# Switch the choice\nvalue.set(String(\"world\"))\ninner = value.unwrap()           # Get the inner value\n\n# Named choice with custom keys\nclass Result(Choice):\n    success: String\n    error: U8\n\nresult = Result(String(\"OK\"))\nresult = Result(U8(404), key=\"error\")\n\n# JSON serialization\njson_data = result.to_json()     # {\"success\": \"OK\"} or {\"error\": 404}\nrestored = Result.from_json(json_data)\n\n# Encoding\nencoded = result.encode()        # [variant_index][value]\ndecoded = Result.decode(encoded)\n```\n\n#### Option (Optional Value - T | Null)\n\n```python\nfrom tsrkit_types.option import Option\nfrom tsrkit_types.integers import U32\n\n# Optional value\nopt_val = Option[U32](U32(100))  # Some value\nempty_opt = Option[U32]()        # None/Null\n\n# Check if has value\nif opt_val:                      # Truthiness test\n    value = opt_val.unwrap()     # Get the U32 value\n\n# Encoding (more efficient than general Choice)\nencoded = opt_val.encode()       # 1 byte tag + optional value\ndecoded = Option[U32].decode(encoded)\n```\n\n### Container Types\n\n#### Sequences (Extension of Python list)\n\n```python\nfrom tsrkit_types.sequences import Array, Vector, TypedArray, TypedVector\nfrom tsrkit_types.integers import U16\n\n# Fixed-size array\nFixedArray = Array[10]           # Array of exactly 10 elements\narr = FixedArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n\n# Typed fixed-size array  \nTypedFixedArray = TypedArray[U16, 5]  # 5 U16 elements\ntyped_arr = TypedFixedArray([U16(1), U16(2), U16(3), U16(4), U16(5)])\n\n# Variable-size vector\nDynamicVector = Vector[100]       # Vector with max 100 elements\nvec = DynamicVector([1, 2, 3])\n\n# Typed variable-size vector\nTypedDynamicVector = TypedVector[U16]  # Vector of U16 elements\ntyped_vec = TypedDynamicVector([U16(1), U16(2)])\n\n# Operations\nvec.append(4)                    # Add element with validation\nvec.extend([5, 6, 7])           # Add multiple elements\nvec[0] = 100                    # Set element with validation\n\n# Encoding\nencoded = typed_vec.encode()     # [length?][element1][element2]...\ndecoded = TypedDynamicVector.decode(encoded)\n```\n\n**Sequence Types:**\n- `Array[N]`: Fixed size, any element type\n- `Vector`: Variable size, any element type  \n- `TypedArray[T, N]`: Fixed size with typed elements\n- `TypedVector[T]`: Variable size with typed elements\n- `BoundedVector[min, max]`: Size constrained vector\n- `TypedBoundedVector[T, min, max]`: Typed and size constrained\n\n#### Dictionary\n\n```python\nfrom tsrkit_types.dictionary import Dictionary\nfrom tsrkit_types.string import String\nfrom tsrkit_types.integers import U32\n\n# Create dictionary type\nStringToInt = Dictionary[String, U32]\ndata = StringToInt({\n    String(\"key1\"): U32(100),\n    String(\"key2\"): U32(200)\n})\n\n# Operations\ndata[String(\"key3\")] = U32(300)   # Add entry\nvalue = data[String(\"key1\")]      # Get value\ndel data[String(\"key2\")]          # Remove entry\n\n# Iteration\nfor key, value in data.items():\n    print(f\"{key}: {value}\")\n\n# Encoding\nencoded = data.encode()           # [length][key1][value1][key2][value2]...\ndecoded = StringToInt.decode(encoded)\n\n# JSON serialization\njson_data = data.to_json()        # {\"key1\": 100, \"key3\": 300}\nrestored = StringToInt.from_json(json_data)\n```\n\n### Bytes Types\n\nThe library provides two complementary byte array types: immutable `Bytes` (extending Python's built-in `bytes`) and mutable `ByteArray` (extending Python's `bytearray`). Both types share common functionality through a mixin architecture for bit conversion, JSON serialization, and binary encoding.\n\n#### Bytes (Immutable - extension of Python bytes)\n\n```python\nfrom tsrkit_types.bytes import Bytes\n\n# Creation\ndata = Bytes(b\"Hello, binary world!\")\ndata = Bytes([0x01, 0x02, 0x03, 0x04])\ndata = Bytes(\"48656c6c6f\")        # From hex string\n\n# Shared Operations (via BytesMixin)\nbits = data.to_bits()            # Convert to bit list [True, False, True, ...]\ndata2 = Bytes.from_bits(bits)    # Create from bit list\n\n# Properties\nlength = len(data)               # Byte length\nraw_bytes = bytes(data)         # Convert to Python bytes\n\n# Encoding/Decoding\nencoded = data.encode()          # [length][raw_bytes]\ndecoded = Bytes.decode(encoded)\n\n# JSON serialization (hex encoded)\njson_str = data.to_json()        # \"48656c6c6f2c2062696e61727920776f726c6421\"\nrestored = Bytes.from_json(json_str)\nrestored2 = Bytes.from_json(\"0x48656c6c6f\")  # Supports 0x prefix\n```\n\n#### ByteArray (Mutable - extension of Python bytearray)\n\n```python\nfrom tsrkit_types.bytearray import ByteArray\n\n# Creation\ndata = ByteArray(b\"Hello, binary world!\")\ndata = ByteArray([0x01, 0x02, 0x03, 0x04])\ndata = ByteArray(\"48656c6c6f\")   # From hex string\n\n# Mutable Operations\ndata.append(0xFF)                # Add single byte\ndata.extend([0xAB, 0xCD])       # Add multiple bytes\ndata.insert(0, 0x00)            # Insert byte at position\ndata.pop()                      # Remove and return last byte\ndata.remove(0xFF)               # Remove first occurrence\ndata.clear()                    # Remove all bytes\ndata.reverse()                  # Reverse in-place\n\n# Indexing and Slicing (mutable)\ndata[0] = 0x42                  # Set byte at index\ndata[1:3] = [0x43, 0x44]       # Set slice\ndel data[0]                     # Delete byte at index\n\n# Shared Operations (via BytesMixin) - same as Bytes\nbits = data.to_bits()           # Convert to bit list\ndata2 = ByteArray.from_bits(bits)  # Create from bit list\n\n# Properties and Conversion\nlength = len(data)              # Byte length  \nraw_bytes = bytes(data)         # Convert to immutable bytes\nimmutable = Bytes(data)         # Convert to immutable Bytes\n\n# Encoding/Decoding (same interface as Bytes)\nencoded = data.encode()         # [length][raw_bytes]\ndecoded = ByteArray.decode(encoded)\n\n# JSON serialization (same interface as Bytes)\njson_str = data.to_json()       # \"48656c6c6f...\"\nrestored = ByteArray.from_json(json_str)\n```\n\n**Key Differences:**\n- **Bytes**: Immutable, extends `bytes`, memory-efficient for read-only data\n- **ByteArray**: Mutable, extends `bytearray`, suitable for dynamic byte manipulation\n- **Shared Functionality**: Both support identical bit conversion, JSON serialization, and binary encoding through `BytesMixin`\n\n**Common Features (Both Types):**\n- Bit-level conversion with MSB/LSB support\n- Hex string JSON serialization with 0x prefix support\n- Efficient binary encoding with length prefix\n- String representation and validation\n- Memory-efficient operations\n\n#### Bits (Bit Arrays - Sequence of bool)\n\n```python\nfrom tsrkit_types.bits import Bits\n\n# Creation\nbits = Bits([True, False, True, True, False])\nbits = Bits.from_hex(\"1A3F\")       # From hex string\nbits = Bits.from_int(42, 8)        # From integer with bit width\n\n# Fixed-size parameterized bits\nFixedBits = Bits[8]                # Exactly 8 bits\nfixed = FixedBits([True, False, True, True, False, False, True, False])\n\n# Operations\nbit_val = bits[0]                  # Get bit at index\nbits[1] = True                     # Set bit at index\nbits.append(False)                 # Add bit\nbits.extend([True, False])         # Add multiple bits\n\n# Conversion\nhex_str = bits.to_hex()            # Convert to hex string\nint_val = bits.to_int()            # Convert to integer\n\n# Bit order specification\nbits_msb = Bits([True, False], bit_order=\"MSB\")  # Most significant bit first\nbits_lsb = Bits([True, False], bit_order=\"LSB\")  # Least significant bit first\n\n# Encoding\nencoded = bits.encode()            # [length][packed_bits]\ndecoded = Bits.decode(encoded)\n\n# JSON serialization\njson_str = bits.to_json()          # Hex string representation\nrestored = Bits.from_json(json_str)\n```\n\n### Enum (Extension of Python Enum, with Codable + JSON support)\n\n```python\nfrom tsrkit_types.enum import Enum\n\n# Define enum\nclass Color(Enum):\n    RED = 0\n    GREEN = 1\n    BLUE = 2\n\n# Usage\ncolor = Color.RED\ncolor_val = Color(1)             # Color.GREEN\n\n# String conversion\nname = color.name                # \"RED\"\nvalue = color.value              # 0\n\n# Encoding\nencoded = color.encode()         # Variable-length uint encoding\ndecoded = Color.decode(encoded)\n\n# JSON serialization\njson_data = color.to_json()      # \"RED\"\nrestored = Color.from_json(\"GREEN\")\n```\n\n### Structured Types\n\n#### Struct Decorator (Extension of dataclasses)\n\n```python\nfrom tsrkit_types.struct import struct\nfrom tsrkit_types.string import String\nfrom tsrkit_types.integers import U8, U32\nfrom dataclasses import field\n\n@structure\nclass Person:\n    name: String\n    age: U8\n    \n@structure  \nclass Employee:\n    person: Person\n    employee_id: U32\n    department: String = field(metadata={\"default\": String(\"Unknown\")})\n\n# Creation\nperson = Person(name=String(\"John Doe\"), age=U8(30))\nemployee = Employee(\n    person=person,\n    employee_id=U32(12345),\n    department=String(\"Engineering\")\n)\n\n# Access fields\nprint(employee.person.name)      # \"John Doe\"\nprint(employee.employee_id)      # 12345\n\n# Encoding/Decoding\nencoded = employee.encode()      # Concatenated field encodings\ndecoded = Employee.decode(encoded)\n\n# JSON serialization with custom field names\n@structure\nclass CustomPerson:\n    name: String = field(metadata={\"name\": \"full_name\"})\n    age: U8\n\nperson = CustomPerson(name=String(\"Jane\"), age=U8(25))\njson_data = person.to_json()     # {\"full_name\": \"Jane\", \"age\": 25}\nrestored = CustomPerson.from_json({\"full_name\": \"Jane\", \"age\": 25})\n```\n\n**Struct Features:**\n- Automatic `Codable` implementation\n- Field validation and type checking\n- Default values via metadata\n- Custom JSON field mapping\n- Inheritance support\n- Frozen/immutable variants\n\n## Advanced Usage\n\n### Custom Types\n\nImplement your own `Codable` types:\n\n```python\nfrom tsrkit_types.itf.codable import Codable\nfrom typing import Tuple, Union\n\nclass Point3D(Codable):\n    def __init__(self, x: float, y: float, z: float):\n        self.x, self.y, self.z = x, y, z\n    \n    def encode_size(self) -> int:\n        return 24  # 3 doubles = 24 bytes\n    \n    def encode_into(self, buffer: bytearray, offset: int = 0) -> int:\n        import struct\n        struct.pack_into('<ddd', buffer, offset, self.x, self.y, self.z)\n        return 24\n    \n    @classmethod\n    def decode_from(cls, buffer: Union[bytes, bytearray, memoryview], \n                   offset: int = 0) -> Tuple['Point3D', int]:\n        import struct\n        x, y, z = struct.unpack_from('<ddd', buffer, offset)\n        return cls(x, y, z), 24\n```\n\n### Configuration and Optimization\n\n```python\n# Optimize for specific use cases\n@structure(frozen=True)             # Immutable structs\nclass ImmutableData:\n    value: U64\n\n# Memory-efficient sequences\nCompactArray = TypedArray[U8, 1000]  # 1000 bytes exactly\ndata = CompactArray([0] * 1000)\n\n# Bounded containers for validation\nBoundedList = BoundedVector[10, 100]  # Between 10 and 100 elements\nsafe_list = BoundedList([0] * 50)\n```\n\n### Error Handling\n\n```python\nfrom tsrkit_types.integers import U8\n\ntry:\n    # Value out of range\n    invalid = U8(256)               # Raises ValueError\nexcept ValueError as e:\n    print(f\"Range error: {e}\")\n\ntry:\n    # Type mismatch in Choice\n    choice = Choice[U8, String](42) # Raises TypeError\nexcept TypeError as e:\n    print(f\"Type error: {e}\")\n\ntry:\n    # Buffer too small for decoding\n    corrupted = b\"\\x01\"\n    U32.decode(corrupted)           # Raises ValueError\nexcept ValueError as e:\n    print(f\"Decode error: {e}\")\n```\n\n\n## Core Interface\n\nAll types implement the `Codable` interface:\n\n```python\nfrom tsrkit_types.itf.codable import Codable\n\nclass MyType(Codable):\n    def encode_size(self) -> int: ...      # Size needed for encoding\n    def encode_into(self, buffer: bytearray, offset: int = 0) -> int: ...  # Encode into buffer\n    def encode(self) -> bytes: ...         # Encode to new bytes object\n    \n    @classmethod\n    def decode_from(cls, buffer: bytes, offset: int = 0) -> Tuple[T, int]: ...  # Decode from buffer\n    @classmethod\n    def decode(cls, buffer: bytes, offset: int = 0) -> T: ...  # Decode from buffer (convenience)\n```\n\n## Performance Considerations\n\n### Encoding Efficiency\n\n- **Fixed-size types** (U8, U16, etc.) have constant encoding size\n- **Variable-size types** (general Uint) optimize for smaller values\n- **Sequences** encode length only when necessary (variable-size)\n- **Strings** use UTF-8 encoding with variable-length prefix\n\n### Memory Usage\n\n- Types extend built-in Python types where possible (int, str, list, dict)\n- Zero-copy operations where feasible\n- Minimal overhead for type metadata\n\n### Best Practices\n\n```python\n# Prefer fixed-size types when range is known\nuser_id = U32(123456)            # Better than Uint(123456)\n\n# Use typed containers for homogeneous data\nscores = TypedVector[U16]([100, 95, 87, 92])\n\n# Batch operations for better performance\ndata = TypedArray[U8, 1000]([0] * 1000)\nencoded = data.encode()          # Single operation vs. encoding each element\n\n# Reuse buffer for multiple encodings\nbuffer = bytearray(1024)\noffset = 0\noffset += value1.encode_into(buffer, offset)\noffset += value2.encode_into(buffer, offset)\n\n# Choose appropriate byte type for your use case\n# Use Bytes for immutable binary data (memory efficient, read-only)\nconfig_data = Bytes(b\"static configuration\")\n\n# Use ByteArray for dynamic binary buffers (mutable, growing data)\ndynamic_buffer = ByteArray()\ndynamic_buffer.extend([0x01, 0x02])\ndynamic_buffer.append(0x03)\ndynamic_buffer.insert(0, 0x00)  # Result: [0x00, 0x01, 0x02, 0x03]\n```\n\n## Examples\n\n### Network Protocol\n\n```**python**\n@structure\nclass NetworkPacket:\n    packet_type: U8\n    session_id: U32\n    payload_length: U16\n    payload: Bytes\n\n# Create packet\npacket = NetworkPacket(\n    packet_type=U8(1),\n    session_id=U32(0x12345678),\n    payload_length=U16(13),\n    payload=Bytes(b\"Hello, World!\")\n)\n\n# Serialize for transmission\nwire_data = packet.encode()\n\n# Deserialize on receiver\nreceived_packet = NetworkPacket.decode(wire_data)\n```\n\n### Configuration File\n\n```python\n@structure\nclass DatabaseConfig:\n    host: String\n    port: U16\n    username: String \n    password: String\n    max_connections: U8 = field(metadata={\"default\": U8(10)})\n    ssl_enabled: Bool = field(metadata={\"default\": Bool(True)})\n\n# Create config\nconfig = DatabaseConfig(\n    host=String(\"localhost\"),\n    port=U16(5432),\n    username=String(\"admin\"),\n    password=String(\"secret\")\n)\n\n# Save to JSON\nimport json\nwith open(\"db_config.json\", \"w\") as f:\n    json.dump(config.to_json(), f)\n\n# Load from JSON\nwith open(\"db_config.json\", \"r\") as f:\n    data = json.load(f)\n    config = DatabaseConfig.from_json(data)\n```\n\n### Game State Serialization\n\n```python\nclass GameEntityType(Enum):\n    PLAYER = 0\n    ENEMY = 1\n    ITEM = 2\n\n@structure\nclass Position:\n    x: U16\n    y: U16\n\n@structure  \nclass GameEntity:\n    entity_type: GameEntityType\n    position: Position\n    health: U8\n    name: String\n\n@structure\nclass GameState:\n    level: U8\n    score: U32\n    entities: TypedVector[GameEntity]\n\n# Create game state\nstate = GameState(\n    level=U8(1),\n    score=U32(1500),\n    entities=TypedVector[GameEntity]([\n        GameEntity(\n            entity_type=GameEntityType.PLAYER,\n            position=Position(x=U16(100), y=U16(200)),\n            health=U8(100),\n            name=String(\"Hero\")\n        )\n    ])\n)\n\n# Save/load game\nsave_data = state.encode()\nloaded_state = GameState.decode(save_data)\n```\n\n## Development\n\n### Setup\n\n1. **Clone the repository:**\n   ```bash\n   git clone https://github.com/chainscore/tsrkit-types.git\n   cd tsrkit-types\n   ```\n\n2. **Install development dependencies:**\n   ```bash\n   pip install -e \".[dev]\"\n   ```\n\n### Running Tests\n\n**Run the full test suite:**\n```bash\npytest\n```\n\n**Run tests with coverage:**\n```bash\npytest --cov=tsrkit_types --cov-report=html\n```\n\n**Run tests in parallel (faster):**\n```bash\npytest -n auto\n```\n\n**Run specific test categories:**\n```bash\npytest tests/test_integers.py      # Integer type tests\npytest tests/test_strings.py       # String type tests  \npytest tests/test_containers.py    # Container type tests\npytest tests/test_structs.py       # Struct tests\npytest tests/test_network.py       # Network protocol tests\n```\n\n**Run tests with verbose output:**\n```bash\npytest -v\n```\n\n**Skip slow tests:**\n```bash\npytest -m \"not slow\"\n```\n\n### Build and Publish\n\n1. Build the package:\n\n```bash\npython3 -m build --wheel\n```\n\n2. Publish the wheels:\n\n```bash\ntwine upload dist/*\n```\n\n### Test Coverage\n\nView the test coverage report:\n```bash\n# Generate HTML coverage report\npytest --cov=tsrkit_types --cov-report=html\nopen htmlcov/index.html  # macOS\n# or xdg-open htmlcov/index.html  # Linux\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## Requirements\n\n- **Python**: >= 3.11\n- **Runtime Dependencies**: None (zero dependencies!)\n- **Development Dependencies**: pytest and plugins (see `pyproject.toml`) \n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Performant Python Typings library for type-safe binary serialization, JSON encoding, and data validation with zero dependencies",
    "version": "0.1.8",
    "project_urls": {
        "Changelog": "https://github.com/chainscore/tsrkit-types/blob/main/CHANGELOG.md",
        "Documentation": "https://github.com/chainscore/tsrkit-types#readme",
        "Homepage": "https://github.com/chainscore/tsrkit-types",
        "Issues": "https://github.com/chainscore/tsrkit-types/issues",
        "Repository": "https://github.com/chainscore/tsrkit-types"
    },
    "split_keywords": [
        "serialization",
        " binary",
        " encoding",
        " types",
        " codable",
        " json",
        " validation",
        " data-types",
        " type-safety",
        " zero-copy",
        " protocol",
        " struct",
        " networking",
        " performance",
        " bytes",
        " integers",
        " strings"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "88667f87bb24f00d18a4d526f4f511d685d0bba584795b04e158b490ed1cd98a",
                "md5": "19bc768455bc47890ea449cb5fe18205",
                "sha256": "5cf4f86aba2a356ec354e7a47b8504e1efe921ca793e904094cb42cb07cd57ee"
            },
            "downloads": -1,
            "filename": "tsrkit_types-0.1.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "19bc768455bc47890ea449cb5fe18205",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 28873,
            "upload_time": "2025-07-11T06:47:43",
            "upload_time_iso_8601": "2025-07-11T06:47:43.093188Z",
            "url": "https://files.pythonhosted.org/packages/88/66/7f87bb24f00d18a4d526f4f511d685d0bba584795b04e158b490ed1cd98a/tsrkit_types-0.1.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-11 06:47:43",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "chainscore",
    "github_project": "tsrkit-types",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "tsrkit-types"
}
        
Elapsed time: 1.42485s