Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes are recorded here. This project follows Semantic Versioning.

## [Unreleased]

## [0.1.2] - 2026-09-17

### Added

- Add `LexKey.AsMemory()` for allocation-free integration with memory-oriented storage APIs.

## [0.1.1] - 2026-09-17

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<Deterministic>true</Deterministic>
<EnablePackageValidation>true</EnablePackageValidation>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<PackageVersion>0.1.1</PackageVersion>
<PackageVersion>0.1.2</PackageVersion>
<Version>$(PackageVersion)</Version>
<InformationalVersion>$(PackageVersion)</InformationalVersion>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ UUIDs, time values, composites, and storage ranges.
The package is published to Cntryl's GitHub Packages feed:

```xml
<PackageReference Include="Cntryl.LexKey" Version="0.1.1" />
<PackageReference Include="Cntryl.LexKey" Version="0.1.2" />
```

The package namespace is `Cntryl.Keys` so the primary type remains the unambiguous
Expand Down Expand Up @@ -45,6 +45,8 @@ The composite convenience API uses typed, stack-friendly descriptors and allocat
the immutable result for strings, numbers, UUIDs, existing keys, and custom encoders.
The reusable encoder can write without managed allocations after its buffer reaches capacity;
materializing a `LexKey` or array intentionally creates an owned copy.
Use `AsMemory()` to pass an encoded key to memory-oriented storage APIs such as Fitz without
copying; use `ToArray()` only when the caller needs mutable ownership.

## Range helpers

Expand Down
2 changes: 1 addition & 1 deletion smoke/LexKey.PackageConsumer/LexKey.PackageConsumer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LexKeySmokePackageVersion Condition="'$(LexKeySmokePackageVersion)' == ''">0.1.1</LexKeySmokePackageVersion>
<LexKeySmokePackageVersion Condition="'$(LexKeySmokePackageVersion)' == ''">0.1.2</LexKeySmokePackageVersion>
<RestorePackagesPath>$(MSBuildThisFileDirectory)../../artifacts/consumer-package-cache</RestorePackagesPath>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<ILLinkTreatWarningsAsErrors>true</ILLinkTreatWarningsAsErrors>
Expand Down
2 changes: 2 additions & 0 deletions smoke/LexKey.PackageConsumer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
var key = LexKey.EncodeComposite("tenant", 42L, true);
if (key.ToHexString() != "74656e616e7400800000000000002a0001")
throw new InvalidOperationException("Packed composite encoding did not match the contract.");
if (!key.AsMemory().Span.SequenceEqual(key.AsSpan()))
throw new InvalidOperationException("The allocation-free memory view did not match the encoded key.");

var uuid = LexKey.EncodeGuid(Guid.Parse("550e8400-e29b-41d4-a716-446655440000"));
if (uuid.ToHexString() != "550e8400e29b41d4a716446655440000")
Expand Down
3 changes: 3 additions & 0 deletions src/LexKey/LexKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ public sealed class LexKey : IComparable<LexKey>, IEquatable<LexKey>, ILexKeyEnc
/// <summary>Returns a read-only view of the encoded bytes.</summary>
public ReadOnlySpan<byte> AsSpan() => _bytes;

/// <summary>Returns an allocation-free read-only memory view of the encoded bytes.</summary>
public ReadOnlyMemory<byte> AsMemory() => _bytes;

/// <summary>Returns an owned copy of the encoded bytes.</summary>
public byte[] ToArray() => _bytes.ToArray();

Expand Down
1 change: 1 addition & 0 deletions src/LexKey/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable enable
Cntryl.Keys.LexKey.AsMemory() -> System.ReadOnlyMemory<byte>
Cntryl.Keys.Encoder
Cntryl.Keys.Encoder.AsSpan() -> System.ReadOnlySpan<byte>
Cntryl.Keys.Encoder.Clear() -> void
Expand Down
15 changes: 15 additions & 0 deletions test/LexKey.Tests/RangeAndValueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,21 @@ public void ShouldCloneInputsAndOutputsGivenImmutableKey()
Assert.Equal(new byte[] { 1, 2, 3 }, key.ToArray());
}

[Fact]
public void ShouldExposeReadOnlyMemoryWithoutCopyGivenImmutableKey()
{
// Arrange
var key = LexKey.FromBytes([1, 2, 3]);

// Act
var first = key.AsMemory();
var second = key.AsMemory();

// Assert
Assert.True(first.Equals(second));
Assert.Equal(new byte[] { 1, 2, 3 }, first.ToArray());
}

[Fact]
public void ShouldCloneCallerOwnedBytesGivenCompositePart()
{
Expand Down