Skip to content

Commit bf53f2e

Browse files
committed
Release FsCodec.SystemTextJson 3.1.0-rc.4
Add Encoding.GetStringUtf8
1 parent c8571a6 commit bf53f2e

File tree

11 files changed

+32
-21
lines changed

11 files changed

+32
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The `Unreleased` section name is replaced by the expected version of next releas
1616
### Fixed
1717

1818
<a name="3.1.0"></a>
19-
## [3.1.0] - rc.3: 2025-01-29
19+
## [3.1.0] - rc.4: 2025-02-05
2020

2121
### Added
2222

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ module Streams =
859859
// as we know our event bodies are all UTF8 encoded JSON, we can render the string as a log event property
860860
// alternately, you can render the EventBody directly and ensure you have appropriate type destructuring configured
861861
let private render (x: EventBody): string =
862-
System.Text.Encoding.UTF8.GetString(x.Span)
862+
FsCodec.Encoding.GetStringUtf8 x
863863
/// Uses the supplied codec to decode the supplied event record `x`
864864
/// (iff at LogEventLevel.Debug, detail fails to `log` citing the `streamName` and body)
865865
let decode<'E> (log: Serilog.ILogger) (codec: Codec<'E>) (streamName: FsCodec.StreamName) (x: Event) =
@@ -1094,7 +1094,7 @@ module StoreWithMeta =
10941094
// the metadata is encoded as the normal bodies are
10951095
let down ((_index, meta : Metadata, event : 'E) : Event<'E>) =
10961096
struct (event, ValueSome meta, ValueNone)
1097-
Codec.Create<Event<'E>, 'E, Metadata>(up, down, serdes = Store.serdes)
1097+
Codec.Create<Event<'E>, 'E, Metadata>(up, down, serdes = Store.serdes)
10981098
```
10991099

11001100
The above embeds and/or extracts contextual information from the Event's `Meta` field.
@@ -1254,13 +1254,13 @@ module StreamsWithMeta =
12541254
12551255
// no special requirements for deserializing metadata, so use Default Serdes
12561256
let private serdes = Serdes.Default
1257-
let codec<'E when 'E :> TypeShape.UnionContract.IUnionContract> : Codec<'E> =
1257+
let codec<'E when 'E :> TypeShape.UnionContract.IUnionContract>: Codec<'E> =
12581258
// here we surface some metadata from the raw event as part of the application level type
12591259
let up (raw : Streams.Event) (contract : 'E) : Event<'E> =
12601260
struct (raw.Index, serdes.Deserialize<Metadata> raw.Meta, contract)
12611261
// We are not using this codec to encode events, so we let the encoding side fail very fast
12621262
let down _ = failwith "N/A"
1263-
Codec.Create<Event<'E>, 'E, Metadata>(up, down, options = Store.options)
1263+
Codec.Create<Event<'E>, 'E, Metadata>(up, down, options = Store.options) |> FsCodec.Encoder.Uncompressed
12641264
```
12651265

12661266
Then, per the relevant Event contract, we define a Decode pattern to decode relevant events from the stream, if this event is relevant for us:

src/FsCodec.Box/Compression.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ type [<Struct>] CompressionOptions = { minSize: int; minGain: int } with
88
static member Default = { minSize = 48; minGain = 4 }
99
static member Uncompressed = { minSize = Int32.MaxValue; minGain = 0 }
1010

11-
[<Extension; AbstractClass; Sealed; Obsolete "Please use FsCodec.Encoding instead">]
11+
[<Extension; AbstractClass; Sealed; Obsolete "Please use FsCodec.Encoder instead">]
1212
type Compression private () =
1313

1414
static member Utf8ToEncodedDirect(x: ReadOnlyMemory<byte>): Encoded =
@@ -17,6 +17,7 @@ type Compression private () =
1717
FsCodec.Encoding.OfBlobCompress({ minSize = options.minSize; minGain = options.minGain }, x)
1818
static member EncodedToUtf8(x: Encoded): ReadOnlyMemory<byte> =
1919
FsCodec.Encoding.ToBlob x
20+
/// NOTE if this is for use with System.Text.Encoding.UTF8.GetString, then EncodedToUtf8 >> _.Span is more efficient
2021
static member EncodedToByteArray(x: Encoded): byte[] =
2122
FsCodec.Encoding.ToBlob(x).ToArray()
2223

src/FsCodec.NewtonsoftJson/FsCodec.NewtonsoftJson.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
<ItemGroup>
3232
<ProjectReference Condition=" '$(Configuration)' == 'Debug' " Include="../FsCodec.Box/FsCodec.Box.fsproj" />
33-
<PackageReference Condition=" '$(Configuration)' == 'Release' " Include="FsCodec.Box" Version="[3.0.0, 4.0.0)" />
33+
<PackageReference Condition=" '$(Configuration)' == 'Release' " Include="FsCodec.Box" Version="[3.1.0-rc.3, 4.0.0)" />
3434
</ItemGroup>
3535

3636
</Project>

src/FsCodec.NewtonsoftJson/Serdes.fs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ type Serdes(options: JsonSerializerSettings) =
7979
use jsonReader = Utf8BytesEncoder.makeJsonReader ms
8080
serializer.Deserialize<'T>(jsonReader)
8181

82+
/// Deserializes value of given type from a (potentially compressed) Encoded value
83+
member x.Deserialize<'T>(utf8Encoded: FsCodec.Encoded): 'T =
84+
x.Deserialize<'T>(FsCodec.Encoding.ToBlob utf8Encoded)
85+
8286
/// Deserializes value of given type from a JObject
8387
member _.Deserialize<'T>(parsed: Newtonsoft.Json.Linq.JObject): 'T =
8488
parsed.ToObject(typeof<'T>, serializer) :?> 'T

src/FsCodec.SystemTextJson/Serdes.fs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ type Serdes(options: JsonSerializerOptions) =
4747
member x.Deserialize<'T>(utf8json: System.ReadOnlyMemory<byte>): 'T =
4848
x.Deserialize<'T>(utf8json.Span)
4949

50+
/// Deserializes value of given type from a (potentially compressed) Encoded value
51+
member x.Deserialize<'T>(utf8Encoded: FsCodec.Encoded): 'T =
52+
x.Deserialize<'T>(FsCodec.Encoding.ToBlob utf8Encoded)
53+
5054
/// Deserializes by reading from a stream.
5155
member _.DeserializeFromStream<'T>(utf8Stream: Stream): 'T =
5256
JsonSerializer.Deserialize<'T>(utf8Stream, options)

src/FsCodec/Encoding.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ type Encoding private () =
7575
Impl.tryCompress options.minSize options.minGain x
7676
static member ToBlob(x: Encoded): ReadOnlyMemory<byte> =
7777
Impl.decode x
78+
static member GetStringUtf8(x: Encoded): string =
79+
System.Text.Encoding.UTF8.GetString(Encoding.ToBlob(x).Span)
7880
static member ByteCount((_encoding, data): Encoded) =
7981
data.Length
8082

tests/FsCodec.NewtonsoftJson.Tests/Examples.fsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// dotnet build tests/FsCodec.NewtonsoftJson.Tests before attempting to send this to FSI with Alt-Enter
33

44
#if !USE_LOCAL_BUILD
5-
#I "bin/Debug/net6.0"
5+
#I "bin/Debug/net9.0"
66
#r "FsCodec.dll"
77
#r "Newtonsoft.Json.dll"
88
#r "FsCodec.NewtonsoftJson.dll"

tests/FsCodec.SystemTextJson.Tests/EncodingTests.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ module InternalDecoding =
3838
let explicitBrotli = struct (2, JsonSerializer.SerializeToElement "CwuAeyJ2YWx1ZSI6IkhlbGxvIFdvcmxkIn0D")
3939

4040
let decode useRom =
41-
if useRom then FsCodec.SystemTextJson.Encoding.ToUtf8 >> _.ToArray() >> JsonSerializer.Deserialize
41+
if useRom then fun x -> JsonSerializer.Deserialize(FsCodec.SystemTextJson.Encoding.ToUtf8(x).Span)
4242
else FsCodec.SystemTextJson.Encoding.ToJsonElement >> JsonSerializer.Deserialize
4343

4444
let [<Theory; InlineData false; InlineData true>] ``Can decode all known representations`` useRom =

tests/FsCodec.SystemTextJson.Tests/Examples.fsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#if !USE_LOCAL_BUILD
55
(* Rider's FSI is not happy without the explicit references :shrug: *)
6-
#I "bin/Debug/net6.0"
6+
#I "bin/Debug/net9.0"
77
#r "FsCodec.dll"
88
#r "System.Text.Json.dll"
99
#r "FsCodec.SystemTextJson.dll"
@@ -208,7 +208,7 @@ module Events =
208208
interface TypeShape.UnionContract.IUnionContract
209209
let codec = Store.codec<Event>
210210

211-
let utf8 (s: string) = System.Text.Encoding.UTF8.GetBytes(s) |> ReadOnlyMemory
211+
let utf8 (s: string) = System.Text.Encoding.UTF8.GetBytes(s) |> FsCodec.Encoding.OfBlob
212212
let streamForClient c = Stream.name (ClientId.parse c)
213213
let events = [
214214
Stream.name (ClientId.parse "ClientA"), FsCodec.Core.TimelineEvent.Create(0L, "Added", utf8 """{ "item": "a" }""")
@@ -235,13 +235,13 @@ Log.initWithDebugLevel ()
235235

236236
(* Explicit matching, showing how some ugly things get into the code if you do the streamName matching and event parsing separately *)
237237

238-
// When we obtain events from an event store via streaming notifications, we typically receive them as ReadOnlyMemory<byte> bodies
238+
// When we obtain events from an event store via streaming notifications, we typically receive them as FsCodec.Encoded or ReadOnlyMemory<byte> bodies
239239
type Event = FsCodec.ITimelineEvent<EventBody>
240-
and EventBody = ReadOnlyMemory<byte>
240+
and EventBody = FsCodec.Encoded
241241
and Codec<'E> = FsCodec.IEventCodec<'E, EventBody, unit>
242242

243243
let streamCodec<'E when 'E :> TypeShape.UnionContract.IUnionContract> : Codec<'E> =
244-
Codec.Create<'E>(serdes = Store.serdes)
244+
Codec.Create<'E>(serdes = Store.serdes) |> FsCodec.Encoder.Uncompressed
245245

246246
let dec = streamCodec<Events.Event>
247247
let [<return:Struct>] (|DecodeEvent|_|) (codec: Codec<'E>) event = codec.Decode event
@@ -299,19 +299,19 @@ module Streams =
299299
// Events coming from streams are carried as a TimelineEvent; the body type is configurable
300300
type Event = FsCodec.ITimelineEvent<EventBody>
301301
// Propulsion's Sinks by default use ReadOnlyMemory<byte> as the storage format
302-
and EventBody = ReadOnlyMemory<byte>
302+
and EventBody = FsCodec.Encoded
303303
// the above Events can be decoded by a Codec implementing this interface
304304
and Codec<'E> = FsCodec.IEventCodec<'E, EventBody, unit>
305305

306306
/// Generates a Codec for the specified Event Union type
307307
let codec<'E when 'E :> TypeShape.UnionContract.IUnionContract> : Codec<'E> =
308308
// Borrowing the Store serdes; frequently the events you parse can use less complex options...
309-
Codec.Create<'E>(serdes = Store.serdes)
309+
Codec.Create<'E>(serdes = Store.serdes) |> FsCodec.Encoder.Uncompressed
310310

311311
// as we know our event bodies are all UTF8 encoded JSON, we can render the string as a log event property
312312
// alternately, you can render the EventBody directly and ensure you have appropriate type destructuring configured
313313
let private render (x: EventBody): string =
314-
System.Text.Encoding.UTF8.GetString(x.Span)
314+
FsCodec.Encoding.GetStringUtf8 x
315315
/// Uses the supplied codec to decode the supplied event record `x`
316316
/// (iff at LogEventLevel.Debug, detail fails to `log` citing the `streamName` and body)
317317
let decode<'E> (log: Serilog.ILogger) (codec: Codec<'E>) (streamName: FsCodec.StreamName) (x: Event) =
@@ -463,11 +463,11 @@ module StreamsWithMeta =
463463

464464
let codec<'E when 'E :> TypeShape.UnionContract.IUnionContract> : Codec<'E> =
465465
// here we surface some metadata from the raw event as part of the application level type
466-
let up (raw: Streams.Event) (contract: 'E): Event<'E> =
466+
let up (raw: FsCodec.ITimelineEvent<ReadOnlyMemory<byte>>) (contract: 'E): Event<'E> =
467467
struct (raw.Index, serdes.Deserialize<Metadata> raw.Meta, contract)
468468
// We are not using this codec to encode events, so we let the encoding side fail very fast
469469
let down _ = failwith "N/A"
470-
Codec.Create<Event<'E>, 'E, Metadata>(up, down, serdes = Store.serdes)
470+
Codec.Create<Event<'E>, 'E, Metadata>(up, down, serdes = Store.serdes) |> FsCodec.Encoder.Uncompressed
471471

472472
let eventsWithMeta = seq {
473473
for sn, e in events ->

0 commit comments

Comments
 (0)