Skip to content

Conversation

@1amageek
Copy link

@1amageek 1amageek commented Nov 1, 2025

Summary

This PR adds two major missing features to the Swift bindings:

  1. Versionstamp support - Full tuple-layer versionstamp implementation
  2. Subspace support - Key namespace management with range operations

These features bring the Swift bindings to parity with Python, Go, and Java bindings, enabling the development of Record Layer and other advanced FoundationDB applications in Swift.

Motivation

The Swift bindings currently lack essential features available in other language bindings, making it difficult to:

  • Use versionstamped keys for temporal ordering
  • Manage key namespaces efficiently
  • Build Record Layer or similar frameworks

This PR addresses these gaps by implementing the missing features following the canonical behavior of official bindings.

Versionstamp Implementation

Core Features

  • Versionstamp struct: 12-byte value (10-byte transaction version + 2-byte user version)
  • Incomplete versionstamps: Support for transaction-time assignment
  • Tuple integration: Full encode/decode support with type code 0x33
  • packWithVersionstamp(): Automatic offset calculation for atomic operations

Usage Example

// Create incomplete versionstamp
let vs = Versionstamp.incomplete(userVersion: 0)
let tuple = Tuple("user", 12345, vs)

// Pack with automatic offset calculation
let key = try tuple.packWithVersionstamp()

// Use with atomic operation
transaction.atomicOp(
    key: key,
    param: value,
    mutationType: .setVersionstampedKey
)

// Read back and decode
let storedKey = try await transaction.get(someKey)
let decoded = try Tuple.decode(from: storedKey)
let versionstamp = decoded[2] as? Versionstamp

Subspace Implementation

Core Features

  • Subspace struct: Key namespace management with tuple encoding
  • range() method: Returns (prefix + [0x00], prefix + [0xFF]) for tuple data
  • strinc() algorithm: String increment for raw binary prefixes
  • prefixRange() method: Complete prefix coverage using strinc

Usage Example

// Create subspace
let userSpace = Subspace(rootPrefix: "users")
let activeUsers = userSpace.subspace("active")

// Pack keys with prefix
let key = activeUsers.pack(Tuple(userId, "name"))

// Range queries
let (begin, end) = activeUsers.range()
let records = try await transaction.getRange(beginKey: begin, endKey: end)

// Raw binary prefix support
let rawSubspace = Subspace(prefix: [0x01, 0xFF])
let (begin, end) = try rawSubspace.prefixRange()  // Uses strinc

Testing

Comprehensive test suite with 150 tests (all passing):

Versionstamp Tests (20)

  • Incomplete/complete versionstamp creation
  • Byte encoding/decoding
  • Tuple packing with offset calculation
  • Roundtrip tests (encode → decode)
  • Error handling

Subspace Tests (22)

  • Range operations (range() and prefixRange())
  • Tuple packing/unpacking
  • Namespace containment checks
  • Edge cases (0xFF handling)

String Increment Tests (14)

  • strinc algorithm correctness
  • Trailing 0xFF handling
  • Cross-language compatibility (Java, Go)
  • Error cases

Integration

  • All tests verified with Swift Testing framework
  • Clean build with no warnings
  • Memory-safe operations

Compatibility

Cross-Language Consistency

This implementation follows the canonical behavior of official bindings:

  • Java: ByteArrayUtil.strinc(), Versionstamp, Subspace
  • Python: fdb.strinc(), fdb.tuple.Versionstamp, tuple packing
  • Go: fdb.Strinc(), fdb.IncompleteVersionstamp(), Subspace.FDBRangeKeys()
  • C++: Range semantics match C++ implementation

API Version

  • Supports API 520+ (4-byte offsets)
  • Dead code for API < 520 removed for clarity
  • Follows modern FoundationDB best practices

Files Changed

New Files

  • Sources/FoundationDB/Versionstamp.swift (196 lines)

    • Core Versionstamp implementation
    • TupleElement conformance
    • Comprehensive documentation
  • Sources/FoundationDB/Tuple+Versionstamp.swift (205 lines)

    • packWithVersionstamp() method
    • Validation and helper methods
    • API 520+ offset handling
  • Sources/FoundationDB/Subspace.swift (424 lines)

    • Subspace implementation
    • range() and prefixRange() methods
    • strinc() algorithm
    • SubspaceError enum
  • Tests/FoundationDBTests/VersionstampTests.swift (416 lines)

  • Tests/FoundationDBTests/SubspaceTests.swift (312 lines)

  • Tests/FoundationDBTests/StringIncrementTests.swift (194 lines)

Modified Files

  • Sources/FoundationDB/Tuple.swift (+3 lines)
    • Add versionstamp case to Tuple.decode() switch
    • Enables automatic versionstamp decoding

Statistics

  • Total additions: ~1,750 lines
  • Test coverage: 56 new tests
  • Documentation: Comprehensive inline documentation for all public APIs

Breaking Changes

None. This PR is purely additive and maintains full backward compatibility with existing code.

Future Work

This PR lays the groundwork for:

  • FoundationDB Record Layer implementation in Swift
  • Directory Layer support
  • Advanced indexing patterns
  • Versionstamp-based temporal queries

Checklist

  • All tests pass (150/150)
  • No build warnings
  • Comprehensive documentation
  • Cross-language compatibility verified
  • Memory-safe implementations
  • Follows Swift API design guidelines
  • Backward compatible

References

This commit adds two major features to the Swift bindings:

## Versionstamp Support
- Implement 12-byte Versionstamp structure (10-byte transaction version + 2-byte user version)
- Add incomplete versionstamp support for transaction-time assignment
- Implement Tuple integration with versionstamp encoding (type code 0x33)
- Add packWithVersionstamp() for atomic operations

## Subspace Implementation
- Implement Subspace for key namespace management with tuple encoding
- Add range() method using prefix + [0x00] / prefix + [0xFF] pattern
- Implement strinc() algorithm for raw binary prefix support
- Add prefixRange() method for complete prefix coverage
- Define SubspaceError for proper error handling

## Testing
- Add VersionstampTests with 15 test cases
- Add StringIncrementTests with 14 test cases for strinc() algorithm
- Add SubspaceTests with 22 test cases covering range() and prefixRange()
- Verify cross-language compatibility with official bindings

All implementations follow the canonical behavior of official Java, Python, Go, and C++ bindings.
This commit completes the Versionstamp implementation by adding
decode support and comprehensive roundtrip tests.

## Tuple.decode() Integration
- Add versionstamp case (0x33) to Tuple.decode() switch
- Enable automatic Versionstamp decoding in tuples
- Allows reading versionstamped keys from database

## Roundtrip Tests
- Add 5 roundtrip tests (encode → decode)
  - Complete versionstamp roundtrip
  - Incomplete versionstamp roundtrip
  - Mixed tuple with multiple types
  - Multiple versionstamps in one tuple
  - Error handling for insufficient bytes

## Test Fixes
- Fix withUnsafeBytes crash by ensuring exact 4-byte array
- Add size validation before unsafe memory access
- Fix range test expectations (prefix vs prefix + [0x00])

## Code Cleanup
- Remove dead code for API < 520 (no longer supported)
- Simplify to single code path using 4-byte offsets
- Update documentation to reflect API 520+ requirement

All 150 tests now pass successfully.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant