From a99ccdb41ce414fa3d06a9c1acdea68ad6fd372d Mon Sep 17 00:00:00 2001 From: SynesthesiaDev_ Date: Fri, 22 May 2026 07:33:24 +0200 Subject: [PATCH 1/2] Change how struct codecs are constructed --- Codon.Codec/StructCodec.cs | 240 +----------------- Codon.Codec/StructCodecBuilder.cs | 254 ++++++++++++++++++++ Codon.Tests/CodecTests.cs | 24 +- Codon.Tests/IniParserTests.cs | 15 +- Codon.Tests/ListMapEnumAndMoreCodecTests.cs | 21 +- Codon.Tests/OptionalAndDefaultCodecTests.cs | 20 +- Codon.Tests/RecursiveCodecTests.cs | 12 +- Codon.Tests/VersionCodecTests.cs | 12 +- 8 files changed, 301 insertions(+), 297 deletions(-) create mode 100644 Codon.Codec/StructCodecBuilder.cs diff --git a/Codon.Codec/StructCodec.cs b/Codon.Codec/StructCodec.cs index 278c9c8..5ef9f39 100644 --- a/Codon.Codec/StructCodec.cs +++ b/Codon.Codec/StructCodec.cs @@ -6,245 +6,7 @@ namespace Codon.Codec; public static class StructCodec { - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - Func func - ) - { - return new StructCodec.StructCodec2P(name1, codec1, getter1, name2, codec2, getter2, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - Func func - ) - { - return new StructCodec.StructCodec3P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - Func func - ) - { - return new StructCodec.StructCodec4P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - Func func - ) - { - return new StructCodec.StructCodec5P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - Func func - ) - { - return new StructCodec.StructCodec6P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - Func func - ) - { - return new StructCodec.StructCodec7P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - Func func - ) - { - return new StructCodec.StructCodec8P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - Func func - ) - { - return new StructCodec.StructCodec9P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - Func func - ) - { - return new StructCodec.StructCodec10P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - Func func - ) - { - return new StructCodec.StructCodec11P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - string name12, Codec codec12, Func getter12, - Func func - ) - { - return new StructCodec.StructCodec12P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, name12, codec12, getter12, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - string name12, Codec codec12, Func getter12, - string name13, Codec codec13, Func getter13, - Func func - ) - { - return new StructCodec.StructCodec13P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, name12, codec12, getter12, name13, codec13, getter13, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - string name12, Codec codec12, Func getter12, - string name13, Codec codec13, Func getter13, - string name14, Codec codec14, Func getter14, - Func func - ) - { - return new StructCodec.StructCodec14P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, name12, codec12, getter12, name13, codec13, getter13, name14, codec14, getter14, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - string name12, Codec codec12, Func getter12, - string name13, Codec codec13, Func getter13, - string name14, Codec codec14, Func getter14, - string name15, Codec codec15, Func getter15, - Func func - ) - { - return new StructCodec.StructCodec15P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, name12, codec12, getter12, name13, codec13, getter13, name14, codec14, getter14, name15, codec15, getter15, func); - } - - public static StructCodec Of( - string name1, Codec codec1, Func getter1, - string name2, Codec codec2, Func getter2, - string name3, Codec codec3, Func getter3, - string name4, Codec codec4, Func getter4, - string name5, Codec codec5, Func getter5, - string name6, Codec codec6, Func getter6, - string name7, Codec codec7, Func getter7, - string name8, Codec codec8, Func getter8, - string name9, Codec codec9, Func getter9, - string name10, Codec codec10, Func getter10, - string name11, Codec codec11, Func getter11, - string name12, Codec codec12, Func getter12, - string name13, Codec codec13, Func getter13, - string name14, Codec codec14, Func getter14, - string name15, Codec codec15, Func getter15, - string name16, Codec codec16, Func getter16, - Func func - ) - { - return new StructCodec.StructCodec16P(name1, codec1, getter1, name2, codec2, getter2, name3, codec3, getter3, name4, codec4, getter4, name5, codec5, getter5, name6, codec6, getter6, name7, codec7, getter7, name8, codec8, getter8, name9, codec9, getter9, name10, codec10, getter10, name11, codec11, getter11, name12, codec12, getter12, name13, codec13, getter13, name14, codec14, getter14, name15, codec15, getter15, name16, codec16, getter16, func); - } + public static StructCodecBuilder For() => new(); } public abstract class StructCodec : Codec diff --git a/Codon.Codec/StructCodecBuilder.cs b/Codon.Codec/StructCodecBuilder.cs new file mode 100644 index 0000000..6e3b195 --- /dev/null +++ b/Codon.Codec/StructCodecBuilder.cs @@ -0,0 +1,254 @@ +// Copyright (c) 2026 SynesthesiaDev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace Codon.Codec; + +public readonly struct StructCodecBuilder +{ + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P1 : notnull + => new(name, codec, getter); +} + +public readonly struct StructCodecBuilder where P1 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + + internal StructCodecBuilder(string name, Codec codec, Func getter) + => (N1, C1, G1) = (name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P2 : notnull + => new(N1, C1, G1, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec1P(N1, C1, G1, factory); +} + +public readonly struct StructCodecBuilder where P1 : notnull where P2 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2) = (n1, c1, g1, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P3 : notnull + => new(N1, C1, G1, N2, C2, G2, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec2P(N1, C1, G1, N2, C2, G2, factory); +} + +public readonly struct StructCodecBuilder where P1 : notnull where P2 : notnull where P3 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3) = (n1, c1, g1, n2, c2, g2, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P4 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec3P(N1, C1, G1, N2, C2, G2, N3, C3, G3, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P5 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec4P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P6 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec5P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + internal readonly string N6; internal readonly Codec C6; internal readonly Func G6; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string n5, Codec c5, Func g5, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, n5, c5, g5, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P7 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec6P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + internal readonly string N6; internal readonly Codec C6; internal readonly Func G6; + internal readonly string N7; internal readonly Codec C7; internal readonly Func G7; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string n5, Codec c5, Func g5, + string n6, Codec c6, Func g6, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, n5, c5, g5, n6, c6, g6, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P8 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec7P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + internal readonly string N6; internal readonly Codec C6; internal readonly Func G6; + internal readonly string N7; internal readonly Codec C7; internal readonly Func G7; + internal readonly string N8; internal readonly Codec C8; internal readonly Func G8; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string n5, Codec c5, Func g5, + string n6, Codec c6, Func g6, + string n7, Codec c7, Func g7, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, n5, c5, g5, n6, c6, g6, n7, c7, g7, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P9 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec8P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull where P9 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + internal readonly string N6; internal readonly Codec C6; internal readonly Func G6; + internal readonly string N7; internal readonly Codec C7; internal readonly Func G7; + internal readonly string N8; internal readonly Codec C8; internal readonly Func G8; + internal readonly string N9; internal readonly Codec C9; internal readonly Func G9; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string n5, Codec c5, Func g5, + string n6, Codec c6, Func g6, + string n7, Codec c7, Func g7, + string n8, Codec c8, Func g8, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, N9, C9, G9) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, n5, c5, g5, n6, c6, g6, n7, c7, g7, n8, c8, g8, name, codec, getter); + + public StructCodecBuilder Field(string name, Codec codec, Func getter) where P10 : notnull + => new(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, N9, C9, G9, name, codec, getter); + + public StructCodec Build(Func factory) + => new StructCodec.StructCodec9P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, N9, C9, G9, factory); +} + +public readonly struct StructCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull where P9 : notnull where P10 : notnull +{ + internal readonly string N1; internal readonly Codec C1; internal readonly Func G1; + internal readonly string N2; internal readonly Codec C2; internal readonly Func G2; + internal readonly string N3; internal readonly Codec C3; internal readonly Func G3; + internal readonly string N4; internal readonly Codec C4; internal readonly Func G4; + internal readonly string N5; internal readonly Codec C5; internal readonly Func G5; + internal readonly string N6; internal readonly Codec C6; internal readonly Func G6; + internal readonly string N7; internal readonly Codec C7; internal readonly Func G7; + internal readonly string N8; internal readonly Codec C8; internal readonly Func G8; + internal readonly string N9; internal readonly Codec C9; internal readonly Func G9; + internal readonly string N10; internal readonly Codec C10; internal readonly Func G10; + + internal StructCodecBuilder( + string n1, Codec c1, Func g1, + string n2, Codec c2, Func g2, + string n3, Codec c3, Func g3, + string n4, Codec c4, Func g4, + string n5, Codec c5, Func g5, + string n6, Codec c6, Func g6, + string n7, Codec c7, Func g7, + string n8, Codec c8, Func g8, + string n9, Codec c9, Func g9, + string name, Codec codec, Func getter) => + (N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, N9, C9, G9, N10, C10, G10) = (n1, c1, g1, n2, c2, g2, n3, c3, g3, n4, c4, g4, n5, c5, g5, n6, c6, g6, n7, c7, g7, n8, c8, g8, n9, c9, g9, name, codec, getter); + + // No .Field() method here since we are capping it at 10 flat properties. + public StructCodec Build(Func factory) + => new StructCodec.StructCodec10P(N1, C1, G1, N2, C2, G2, N3, C3, G3, N4, C4, G4, N5, C5, G5, N6, C6, G6, N7, C7, G7, N8, C8, G8, N9, C9, G9, N10, C10, G10, factory); +} diff --git a/Codon.Tests/CodecTests.cs b/Codon.Tests/CodecTests.cs index 8feb23c..f361da8 100644 --- a/Codon.Tests/CodecTests.cs +++ b/Codon.Tests/CodecTests.cs @@ -11,24 +11,20 @@ public class CodecTests public record Person(string Name, int Age, Optional IsAwesome) { - public static readonly Codec CODEC = StructCodec.Of - ( - "name", Codecs.STRING, p => p.Name, - "age", Codecs.INT, p => p.Age, - "is_awesome", Codecs.BOOLEAN.Optional(), p => p.IsAwesome, - (name, age, someBoolean) => new Person(name, age, someBoolean) - ); + public static readonly StructCodec CODEC = StructCodec.For() + .Field("name", Codecs.STRING, p => p.Name) + .Field("age", Codecs.INT, p => p.Age) + .Field("is_awesome", Codecs.BOOLEAN.Optional(), p => p.IsAwesome) + .Build((name, age, isAwesome) => new Person(name, age, isAwesome)); } public record Car(string Model, List Passengers, Optional Driver) { - public static readonly StructCodec CODEC = StructCodec.Of - ( - "model", Codecs.STRING, c => c.Model, - "passengers", Person.CODEC.List(), c => c.Passengers, - "driver", Person.CODEC.Optional(), c => c.Driver, - (model, passengers, driver) => new Car(model, passengers, driver) - ); + public static readonly StructCodec CODEC = StructCodec.For() + .Field("model", Codecs.STRING, c => c.Model) + .Field("passengers", Person.CODEC.List(), c => c.Passengers) + .Field("driver", Person.CODEC.Optional(), c => c.Driver) + .Build((model, passengers, driver) => new Car(model, passengers, driver)); } [Test] diff --git a/Codon.Tests/IniParserTests.cs b/Codon.Tests/IniParserTests.cs index 869056c..dc4844c 100644 --- a/Codon.Tests/IniParserTests.cs +++ b/Codon.Tests/IniParserTests.cs @@ -12,14 +12,13 @@ public class IniParserTests public record User(string Name, int Age, bool IsTester, List Properties) { - public static readonly Codec CODEC = StructCodec.Of - ( - "name", Codecs.STRING, u => u.Name, - "age", Codecs.INT, u => u.Age, - "is_tester", Codecs.BOOLEAN, u => u.IsTester, - "properties", Codecs.STRING.List(), u => u.Properties, - (name, age, isTester, properties) => new User(name, age, isTester, properties) - ).WithSection("User"); + public static readonly Codec CODEC = StructCodec.For() + .Field("name", Codecs.STRING, u => u.Name) + .Field("age", Codecs.INT, u => u.Age) + .Field("is_tester", Codecs.BOOLEAN, u => u.IsTester) + .Field("properties", Codecs.STRING.List(), u => u.Properties) + .Build((name, age, isTester, properties) => new User(name, age, isTester, properties)) + .WithSection("User"); } [Test] diff --git a/Codon.Tests/ListMapEnumAndMoreCodecTests.cs b/Codon.Tests/ListMapEnumAndMoreCodecTests.cs index 759db27..39228a6 100644 --- a/Codon.Tests/ListMapEnumAndMoreCodecTests.cs +++ b/Codon.Tests/ListMapEnumAndMoreCodecTests.cs @@ -74,13 +74,13 @@ public void TransformativeCodec_RoundTrip() } private abstract record Shape; + private record Rect(int W, int H) : Shape; - private static readonly StructCodec rect_codec = StructCodec.Of( - "w", Codecs.INT, r => r.W, - "h", Codecs.INT, r => r.H, - (w, h) => new Rect(w, h) - ); + private static readonly StructCodec rect_codec = StructCodec.For() + .Field("w", Codecs.INT, r => r.W) + .Field("h", Codecs.INT, r => r.H) + .Build((w, h) => new Rect(w, h)); private enum Kind { Rect } @@ -148,12 +148,11 @@ public void ForwardRefCodec_Delegates() private record Nested(string Name, List Nums, Dictionary Map); - private static readonly StructCodec nested_codec = StructCodec.Of( - "name", Codecs.STRING, n => n.Name, - "nums", Codecs.INT.List(), n => n.Nums, - "map", Codecs.STRING.MapTo(Codecs.INT), n => n.Map, - (name, nums, map) => new Nested(name, nums, map) - ); + private static readonly StructCodec nested_codec = StructCodec.For() + .Field("name", Codecs.STRING, n => n.Name) + .Field("nums", Codecs.INT.List(), n => n.Nums) + .Field("map", Codecs.STRING.MapTo(Codecs.INT), n => n.Map) + .Build((name, nums, map) => new Nested(name, nums, map)); [Test] public void Nested_StructCodec_RoundTrip() diff --git a/Codon.Tests/OptionalAndDefaultCodecTests.cs b/Codon.Tests/OptionalAndDefaultCodecTests.cs index 69166b5..7e76b3d 100644 --- a/Codon.Tests/OptionalAndDefaultCodecTests.cs +++ b/Codon.Tests/OptionalAndDefaultCodecTests.cs @@ -22,28 +22,26 @@ public void Optional_Present_RoundTrip() private record OptHolder(int Id, Optional Oi) { - public static readonly StructCodec CODEC = StructCodec.Of( - "id", Codecs.INT, h => h.Id, - "oi", Codecs.INT.Optional(), h => h.Oi, - (id, oi) => new OptHolder(id, oi) - ); + public static readonly StructCodec CODEC = StructCodec.For() + .Field("id", Codecs.INT, h => h.Id) + .Field("oi", Codecs.INT.Optional(), h => h.Oi) + .Build((id, oi) => new OptHolder(id, oi)); } [Test] public void Optional_Missing_Field_IsEmpty() { - var json = JsonDocument.Parse("{\"id\": 1}" ).RootElement; + var json = JsonDocument.Parse("{\"id\": 1}").RootElement; var decoded = OptHolder.CODEC.Decode(t, json); Assert.That(decoded.Oi.IsMissing, Is.True); } private record DefHolder(int Id, int X) { - public static readonly StructCodec CODEC = StructCodec.Of( - "id", Codecs.INT, h => h.Id, - "x", Codecs.INT.Default(5), h => h.X, - (id, x) => new DefHolder(id, x) - ); + public static readonly StructCodec CODEC = StructCodec.For() + .Field("id", Codecs.INT, h => h.Id) + .Field("x", Codecs.INT.Default(5), h => h.X) + .Build((id, x) => new DefHolder(id, x)); } [Test] diff --git a/Codon.Tests/RecursiveCodecTests.cs b/Codon.Tests/RecursiveCodecTests.cs index c0ef726..31aa865 100644 --- a/Codon.Tests/RecursiveCodecTests.cs +++ b/Codon.Tests/RecursiveCodecTests.cs @@ -8,12 +8,10 @@ public class RecursiveCodecTests public record Node(string Name, List Children) { public static readonly Codec CODEC = Codecs.Recursive(self => - StructCodec.Of( - "name", Codecs.STRING, n => n.Name, - "children", self.List(), n => n.Children, - (name, children) => new Node(name, children) - ) - ); + StructCodec.For() + .Field("name", Codecs.STRING, n => n.Name) + .Field("children", self.List(), n => n.Children) + .Build((name, children) => new Node(name, children))); } [Test] @@ -44,4 +42,4 @@ public void TestRecursiveCodec_EncodeDecodeRoundtrip() Assert.That(decoded.Children[1].Children, Has.Count.EqualTo(1)); Assert.That(decoded.Children[1].Children[0].Name, Is.EqualTo("grandchild1")); } -} \ No newline at end of file +} diff --git a/Codon.Tests/VersionCodecTests.cs b/Codon.Tests/VersionCodecTests.cs index 642444c..1e355a4 100644 --- a/Codon.Tests/VersionCodecTests.cs +++ b/Codon.Tests/VersionCodecTests.cs @@ -13,13 +13,11 @@ public class VersionCodecTests public record Person(string Name, int Age, Optional IsAwesome) { - public static readonly StructCodec CODEC = StructCodec.Of - ( - "name", Codecs.STRING, p => p.Name, - "age", Codecs.INT, p => p.Age, - "is_awesome", Codecs.BOOLEAN.Optional(), p => p.IsAwesome, - (name, age, someBoolean) => new Person(name, age, someBoolean) - ); + public static readonly StructCodec CODEC = StructCodec.For() + .Field("name", Codecs.STRING, p => p.Name) + .Field("age", Codecs.INT, p => p.Age) + .Field("is_awesome", Codecs.BOOLEAN.Optional(), p => p.IsAwesome) + .Build((name, age, someBoolean) => new Person(name, age, someBoolean)); // schema version 0 -> 1: added "age" field // schema version 1 -> 2: renamed "display_name" to just "name" From fa0468e1c571a6af11f12ee45edb857199111a67 Mon Sep 17 00:00:00 2001 From: SynesthesiaDev_ Date: Fri, 22 May 2026 08:13:37 +0200 Subject: [PATCH 2/2] Change how binary codecs are constructed --- Codon.BinaryCodec/BinaryCodec.cs | 348 ----- Codon.BinaryCodec/BinaryCodecBuilder.cs | 255 ++++ Codon.BinaryCodec/BinaryCodecDefinitions.cs | 775 +++++++++++ Codon.BinaryCodec/BinaryCodecs.cs | 1176 +---------------- ...naryCodecTests.cs => BinaryCodecsTests.cs} | 99 +- 5 files changed, 1120 insertions(+), 1533 deletions(-) delete mode 100644 Codon.BinaryCodec/BinaryCodec.cs create mode 100644 Codon.BinaryCodec/BinaryCodecBuilder.cs create mode 100644 Codon.BinaryCodec/BinaryCodecDefinitions.cs rename Codon.Tests/{BinaryCodecTests.cs => BinaryCodecsTests.cs} (63%) diff --git a/Codon.BinaryCodec/BinaryCodec.cs b/Codon.BinaryCodec/BinaryCodec.cs deleted file mode 100644 index cc52cb9..0000000 --- a/Codon.BinaryCodec/BinaryCodec.cs +++ /dev/null @@ -1,348 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using DotNetty.Buffers; - -#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. - -namespace Codon.Binary; - -public static class BinaryCodec -{ - public static readonly BinaryCodec BOOLEAN = new BinaryCodecs.BooleanBinaryCodec(); - - public static readonly BinaryCodec BYTE = new BinaryCodecs.ByteBinaryCodec(); - - public static readonly BinaryCodec INT = new BinaryCodecs.IntBinaryCodec(); - - public static readonly BinaryCodec LONG = new BinaryCodecs.LongBinaryCodec(); - - public static readonly BinaryCodec DOUBLE = new BinaryCodecs.DoubleBinaryCodec(); - - public static readonly BinaryCodec FLOAT = new BinaryCodecs.FloatBinaryCodec(); - - public static readonly BinaryCodec VAR_INT = new BinaryCodecs.VarIntBinaryCodec(); - - public static readonly BinaryCodec BYTE_ARRAY = new BinaryCodecs.ByteArrayBinaryCodec(); - - public static readonly BinaryCodec BYTE_BUFFER = new BinaryCodecs.ByteBufferBinaryCodec(); - - public static readonly BinaryCodec RAW_BYTES = new BinaryCodecs.RawBytesBinaryCodec(); - - public static readonly BinaryCodec STRING = new BinaryCodecs.StringBinaryCodec(); - - public static readonly BinaryCodec GUID = BYTE_ARRAY.Transform(guid => guid.ToByteArray(), bytes => new Guid(bytes)); - - public static BinaryCodecs.RecursiveBinaryCodec Recursive(Func, BinaryCodec> self) where T : notnull => new(self); - - public static BinaryCodec ByteArray(int? maxSize = null) => new BinaryCodecs.ByteArrayBinaryCodec(maxSize); - - public static BinaryCodec ByteBuffer(int? maxSize = null) => new BinaryCodecs.ByteBufferBinaryCodec(maxSize); - - public static BinaryCodecs.EnumBinaryCodec Enum() where E : Enum => new(); - - public static BinaryCodec Flags() where Te : struct, Enum => BYTE.Transform(te => Unsafe.As(ref te), by => Unsafe.As(ref by)); - - public static BinaryCodec String(int maxLength) => new BinaryCodecs.StringBinaryCodec(maxLength); - - public static BinaryCodec Empty(Func func) => new BinaryCodecs.BinaryCodecEmpty(func); - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP1(codec1, getter1, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP2(codec1, getter1, codec2, getter2, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP3(codec1, getter1, codec2, getter2, codec3, getter3, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP4(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP5(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP6(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP7(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP8(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP9(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP10(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP11(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - BinaryCodec codec12, Func getter12, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP12(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, codec12, getter12, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - BinaryCodec codec12, Func getter12, - BinaryCodec codec13, Func getter13, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP13(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, codec12, getter12, codec13, getter13, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - BinaryCodec codec12, Func getter12, - BinaryCodec codec13, Func getter13, - BinaryCodec codec14, Func getter14, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP14(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, codec12, getter12, codec13, getter13, codec14, getter14, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - BinaryCodec codec12, Func getter12, - BinaryCodec codec13, Func getter13, - BinaryCodec codec14, Func getter14, - BinaryCodec codec15, Func getter15, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP15(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, codec12, getter12, codec13, getter13, codec14, getter14, codec15, getter15, func); - } - - public static BinaryCodec Of - ( - BinaryCodec codec1, Func getter1, - BinaryCodec codec2, Func getter2, - BinaryCodec codec3, Func getter3, - BinaryCodec codec4, Func getter4, - BinaryCodec codec5, Func getter5, - BinaryCodec codec6, Func getter6, - BinaryCodec codec7, Func getter7, - BinaryCodec codec8, Func getter8, - BinaryCodec codec9, Func getter9, - BinaryCodec codec10, Func getter10, - BinaryCodec codec11, Func getter11, - BinaryCodec codec12, Func getter12, - BinaryCodec codec13, Func getter13, - BinaryCodec codec14, Func getter14, - BinaryCodec codec15, Func getter15, - BinaryCodec codec16, Func getter16, - Func func - ) - { - return new BinaryCodecs.BinaryCodecP16(codec1, getter1, codec2, getter2, codec3, getter3, codec4, getter4, codec5, getter5, codec6, getter6, codec7, getter7, codec8, getter8, codec9, getter9, codec10, getter10, codec11, getter11, codec12, getter12, codec13, getter13, codec14, getter14, codec15, getter15, codec16, getter16, func); - } -} - -public interface BinaryCodec -{ - void Write(IByteBuffer buffer, T value); - T Read(IByteBuffer buffer); - - BinaryCodecs.OptionalBinaryCodec Optional() - { - return new BinaryCodecs.OptionalBinaryCodec(this); - } - - BinaryCodecs.DefaultBinaryCodec Default(T defaultValue) - { - return new BinaryCodecs.DefaultBinaryCodec(this, defaultValue); - } - - BinaryCodecs.TransformativeBinaryCodec Transform(Func from, Func to) - { - return new BinaryCodecs.TransformativeBinaryCodec(this, from, to); - } - - BinaryCodecs.DictionaryBinaryCodec MapTo(BinaryCodec valueCodec, int? maxSize = null) where V : notnull - { - return new BinaryCodecs.DictionaryBinaryCodec(this, valueCodec, maxSize); - } - - BinaryCodecs.ListBinaryCodec List(int? maxSize = null) - { - return new BinaryCodecs.ListBinaryCodec(this, maxSize); - } - - BinaryCodecs.UnionBinaryCodec Union(Func> serializerFactory, Func keyFunc) where K : notnull - { - return new BinaryCodecs.UnionBinaryCodec(this, keyFunc, serializerFactory); - } -} diff --git a/Codon.BinaryCodec/BinaryCodecBuilder.cs b/Codon.BinaryCodec/BinaryCodecBuilder.cs new file mode 100644 index 0000000..27030b2 --- /dev/null +++ b/Codon.BinaryCodec/BinaryCodecBuilder.cs @@ -0,0 +1,255 @@ +// Copyright (c) 2026 SynesthesiaDev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace Codon.Binary; + +public readonly struct BinaryCodecBuilder +{ + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P1 : notnull + => new(codec, getter); +} + +public readonly struct BinaryCodecBuilder where P1 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + + internal BinaryCodecBuilder(IBinaryCodec codec, Func getter) + => (C1, G1) = (codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P2 : notnull + => new(C1, G1, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP1(C1, G1, factory); +} + +public readonly struct BinaryCodecBuilder where P1 : notnull where P2 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2) = (c1, g1, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P3 : notnull + => new(C1, G1, C2, G2, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP2(C1, G1, C2, G2, factory); +} + +public readonly struct BinaryCodecBuilder where P1 : notnull where P2 : notnull where P3 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3) = (c1, g1, c2, g2, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P4 : notnull + => new(C1, G1, C2, G2, C3, G3, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP3(C1, G1, C2, G2, C3, G3, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4) = (c1, g1, c2, g2, c3, g3, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P5 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP4(C1, G1, C2, G2, C3, G3, C4, G4, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5) = (c1, g1, c2, g2, c3, g3, c4, g4, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P6 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP5(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + internal readonly IBinaryCodec C6; internal readonly Func G6; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec c5, Func g5, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6) = (c1, g1, c2, g2, c3, g3, c4, g4, c5, g5, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P7 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP6(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + internal readonly IBinaryCodec C6; internal readonly Func G6; + internal readonly IBinaryCodec C7; internal readonly Func G7; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec c5, Func g5, + IBinaryCodec c6, Func g6, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7) = (c1, g1, c2, g2, c3, g3, c4, g4, c5, g5, c6, g6, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P8 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP7(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + internal readonly IBinaryCodec C6; internal readonly Func G6; + internal readonly IBinaryCodec C7; internal readonly Func G7; + internal readonly IBinaryCodec C8; internal readonly Func G8; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec c5, Func g5, + IBinaryCodec c6, Func g6, + IBinaryCodec c7, Func g7, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8) = (c1, g1, c2, g2, c3, g3, c4, g4, c5, g5, c6, g6, c7, g7, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P9 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP8(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull where P9 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + internal readonly IBinaryCodec C6; internal readonly Func G6; + internal readonly IBinaryCodec C7; internal readonly Func G7; + internal readonly IBinaryCodec C8; internal readonly Func G8; + internal readonly IBinaryCodec C9; internal readonly Func G9; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec c5, Func g5, + IBinaryCodec c6, Func g6, + IBinaryCodec c7, Func g7, + IBinaryCodec c8, Func g8, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, C9, G9) = (c1, g1, c2, g2, c3, g3, c4, g4, c5, g5, c6, g6, c7, g7, c8, g8, codec, getter); + + public BinaryCodecBuilder Field(IBinaryCodec codec, Func getter) where P10 : notnull + => new(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, C9, G9, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP9(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, C9, G9, factory); +} + +public readonly struct BinaryCodecBuilder + where P1 : notnull where P2 : notnull where P3 : notnull where P4 : notnull where P5 : notnull where P6 : notnull where P7 : notnull where P8 : notnull where P9 : notnull where P10 : notnull +{ + internal readonly IBinaryCodec C1; internal readonly Func G1; + internal readonly IBinaryCodec C2; internal readonly Func G2; + internal readonly IBinaryCodec C3; internal readonly Func G3; + internal readonly IBinaryCodec C4; internal readonly Func G4; + internal readonly IBinaryCodec C5; internal readonly Func G5; + internal readonly IBinaryCodec C6; internal readonly Func G6; + internal readonly IBinaryCodec C7; internal readonly Func G7; + internal readonly IBinaryCodec C8; internal readonly Func G8; + internal readonly IBinaryCodec C9; internal readonly Func G9; + internal readonly IBinaryCodec C10; internal readonly Func G10; + + internal BinaryCodecBuilder( + IBinaryCodec c1, Func g1, + IBinaryCodec c2, Func g2, + IBinaryCodec c3, Func g3, + IBinaryCodec c4, Func g4, + IBinaryCodec c5, Func g5, + IBinaryCodec c6, Func g6, + IBinaryCodec c7, Func g7, + IBinaryCodec c8, Func g8, + IBinaryCodec c9, Func g9, + IBinaryCodec codec, Func getter) => + (C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, C9, G9, C10, G10) = (c1, g1, c2, g2, c3, g3, c4, g4, c5, g5, c6, g6, c7, g7, c8, g8, c9, g9, codec, getter); + + public IBinaryCodec Build(Func factory) + => new BinaryCodecDefinitions.BinaryCodecP10(C1, G1, C2, G2, C3, G3, C4, G4, C5, G5, C6, G6, C7, G7, C8, G8, C9, G9, C10, G10, factory); +} diff --git a/Codon.BinaryCodec/BinaryCodecDefinitions.cs b/Codon.BinaryCodec/BinaryCodecDefinitions.cs new file mode 100644 index 0000000..a11819f --- /dev/null +++ b/Codon.BinaryCodec/BinaryCodecDefinitions.cs @@ -0,0 +1,775 @@ +// Copyright (c) 2026 SynesthesiaDev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Codon.Optionals; +using DotNetty.Buffers; + +namespace Codon.Binary; + +public static class BinaryCodecDefinitions +{ + public class BooleanBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, bool value) + { + buffer.WriteBoolean(value); + } + + public bool Read(IByteBuffer buffer) + { + return buffer.ReadBoolean(); + } + } + + public class ByteBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, byte value) + { + buffer.WriteByte(value); + } + + public byte Read(IByteBuffer buffer) + { + return buffer.ReadByte(); + } + } + + public class IntBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, int value) + { + buffer.WriteInt(value); + } + + public int Read(IByteBuffer buffer) + { + return buffer.ReadInt(); + } + } + + public class LongBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, long value) + { + buffer.WriteLong(value); + } + + public long Read(IByteBuffer buffer) + { + return buffer.ReadLong(); + } + } + + public class FloatBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, float value) + { + buffer.WriteFloat(value); + } + + public float Read(IByteBuffer buffer) + { + return buffer.ReadFloat(); + } + } + + public class DoubleBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, double value) + { + buffer.WriteDouble(value); + } + + public double Read(IByteBuffer buffer) + { + return buffer.ReadDouble(); + } + } + + public class VarIntBinaryCodec : IBinaryCodec + { + private const int segment_bits = 0x7F; + private const int continue_bit = 0x80; + + public void Write(IByteBuffer buffer, int value) + { + var uValue = (uint)value; + while (true) + { + if ((uValue & ~segment_bits) == 0) + { + buffer.WriteByte((byte)uValue); + break; + } + + buffer.WriteByte((byte)((uValue & segment_bits) | continue_bit)); + + uValue >>= 7; + } + } + + public int Read(IByteBuffer buffer) + { + var value = 0; + var position = 0; + + while (position < 35) // Max 5 bytes + { + var currentByte = buffer.ReadByte(); + var segment = currentByte & segment_bits; + + value |= segment << position; + + // finished reading + if ((currentByte & continue_bit) == 0) return value; + + position += 7; + } + + throw new InvalidDataException("VarInt is too long"); + } + } + + public class ByteArrayBinaryCodec(int? maxSize = null) : IBinaryCodec + { + public void Write(IByteBuffer buffer, byte[] value) + { + if (maxSize != null && value.Length > maxSize) + throw new ArgumentException($"The byte array is longer than maximum allowed ({value.Length} > {maxSize})", nameof(value)); + + BinaryCodecs.VAR_INT.Write(buffer, value.Length); + buffer.WriteBytes(value); + } + + public byte[] Read(IByteBuffer buffer) + { + var size = BinaryCodecs.VAR_INT.Read(buffer); + return size > maxSize ? throw new InvalidDataException($"The read byte array is longer than maximum allowed (${size} > {maxSize}") : buffer.ToByteArraySafe(size); + } + } + + public class ByteBufferBinaryCodec(int? maxSize = null) : IBinaryCodec + { + public void Write(IByteBuffer buffer, IByteBuffer value) + { + var size = value.ReadableBytes; + + if (maxSize is not null && size > maxSize.Value) + { + throw new ArgumentException( + $"The byte buffer is longer than maximum allowed ({size} > {maxSize.Value})", + nameof(value)); + } + + BinaryCodecs.VAR_INT.Write(buffer, size); + buffer.WriteBytes(value, value.ReaderIndex, size); + } + + public IByteBuffer Read(IByteBuffer buffer) + { + var size = BinaryCodecs.VAR_INT.Read(buffer); + + if (size < 0) + throw new InvalidDataException($"Size cannot be negative."); + + + if (size > maxSize) + throw new InvalidDataException($"The read byte buffer is longer than maximum allowed (${size} > {maxSize}"); + + return buffer.ReadBytes(size); + } + } + + public class StringBinaryCodec(int? maxStringLength = null) : IBinaryCodec + { + public void Write(IByteBuffer buffer, string value) + { + var stringBytes = Encoding.UTF8.GetBytes(value); + + if (maxStringLength is not null && stringBytes.Length > maxStringLength.Value) + throw new ArgumentException($"String is longer than maximum allowed ({stringBytes.Length} > {maxStringLength.Value})", nameof(value)); + + BinaryCodecs.VAR_INT.Write(buffer, stringBytes.Length); + buffer.WriteBytes(stringBytes); + } + + public string Read(IByteBuffer buffer) + { + var size = BinaryCodecs.VAR_INT.Read(buffer); + + if (size < 0) + throw new InvalidDataException($"The read string has negative length: {size}"); + + if (maxStringLength is not null && size > maxStringLength.Value) + throw new InvalidDataException($"Read string is longer than maximum allowed ({size} > {maxStringLength.Value})"); + + var stringBytes = buffer.ToByteArraySafe(size); + return Encoding.UTF8.GetString(stringBytes); + } + } + + public class RawBytesBinaryCodec : IBinaryCodec + { + public void Write(IByteBuffer buffer, byte[] value) + { + buffer.WriteBytes(value); + } + + public byte[] Read(IByteBuffer buffer) + { + return buffer.ToByteArraySafe(); + } + } + + public class OptionalBinaryCodec(IBinaryCodec innerCodec) : IBinaryCodec> + { + public void Write(IByteBuffer buffer, Optional value) + { + BinaryCodecs.BOOLEAN.Write(buffer, value.IsPresent); + if (value.IsPresent) innerCodec.Write(buffer, value.Value!); + } + + public Optional Read(IByteBuffer buffer) + { + return BinaryCodecs.BOOLEAN.Read(buffer) ? Optional.Of(innerCodec.Read(buffer)) : Optional.Empty(); + } + } + + public class DefaultBinaryCodec(IBinaryCodec innerCodec, T defaultValue) : IBinaryCodec where T : notnull + { + public void Write(IByteBuffer buffer, T? value) + { + BinaryCodecs.BOOLEAN.Write(buffer, value != null); + innerCodec.Write(buffer, value ?? defaultValue); + } + + public T Read(IByteBuffer buffer) + { + return BinaryCodecs.BOOLEAN.Read(buffer) ? innerCodec.Read(buffer) : defaultValue; + } + } + + public class TransformativeBinaryCodec(IBinaryCodec innerCodec, Func from, Func to) : IBinaryCodec where S : notnull where T : notnull + { + public void Write(IByteBuffer buffer, S value) + { + innerCodec.Write(buffer, from.Invoke(value)); + } + + public S Read(IByteBuffer buffer) + { + var innerValue = innerCodec.Read(buffer); + return to.Invoke(innerValue); + } + } + + public class DictionaryBinaryCodec(IBinaryCodec keyCodec, IBinaryCodec valueCodec, int? maxSize = null) : IBinaryCodec> where K : notnull where V : notnull + { + public void Write(IByteBuffer buffer, Dictionary value) + { + + if (maxSize != null && value.Count > maxSize) + throw new ArgumentException($"There are more map entries than maximum allowed ({value.Count} > {maxSize})", nameof(value)); + + BinaryCodecs.VAR_INT.Write(buffer, value.Count); + foreach (var keyValuePair in value) + { + keyCodec.Write(buffer, keyValuePair.Key); + valueCodec.Write(buffer, keyValuePair.Value); + } + } + + public Dictionary Read(IByteBuffer buffer) + { + var dict = new Dictionary(); + var size = BinaryCodecs.VAR_INT.Read(buffer); // how big is my dic(t)... + + if (size < 0) + throw new InvalidDataException($"The read dictionary has negative entry count: {size}"); + + if (maxSize != null && size > maxSize) + throw new InvalidDataException($"The read dictionary has more entries than maximum allowed ({size} > {maxSize})"); + + for (var i = 0; i < size; i++) + { + var key = keyCodec.Read(buffer); + var value = valueCodec.Read(buffer); + dict[key] = value; + } + + return dict; + } + } + + public class ListBinaryCodec(IBinaryCodec innerCodec, int? maxSize = null) : IBinaryCodec> + { + public void Write(IByteBuffer buffer, List value) + { + if (maxSize != null && value.Count > maxSize) + throw new ArgumentException($"There are more list entries than maximum allowed ({value.Count} > {maxSize})", nameof(value)); + + BinaryCodecs.VAR_INT.Write(buffer, value.Count); + value.ForEach(item => innerCodec.Write(buffer, item)); + } + + public List Read(IByteBuffer buffer) + { + var list = new List(); + var size = BinaryCodecs.VAR_INT.Read(buffer); + + if (size < 0) + throw new InvalidDataException($"The read list has negative entry count: {size}"); + + if (size > maxSize) + throw new InvalidDataException($"The read list has more entries than maximum allowed ({size} > {maxSize})"); + + for (var i = 0; i < size; i++) list.Add(innerCodec.Read(buffer)); + + return list; + } + } + + public class UnionBinaryCodec(IBinaryCodec keyCodec, Func keyFunc, Func> serializerFactory) : IBinaryCodec + { + public void Write(IByteBuffer buffer, T value) + { + var key = keyFunc.Invoke(value); + keyCodec.Write(buffer, key); + + var serializer = serializerFactory.Invoke(key); + serializer.Write(buffer, value); + } + + public T Read(IByteBuffer buffer) + { + var key = keyCodec.Read(buffer); + var serializer = serializerFactory.Invoke(key); + return serializer.Read(buffer); + } + } + + public class RecursiveBinaryCodec : IBinaryCodec where T : notnull + { + private readonly Lazy> @delegate; + + public RecursiveBinaryCodec(Func, IBinaryCodec> self) + { + @delegate = new Lazy>(() => self.Invoke(this)); + } + + public void Write(IByteBuffer buffer, T value) + { + @delegate.Value.Write(buffer, value); + } + + public T Read(IByteBuffer buffer) + { + return @delegate.Value.Read(buffer); + } + } + + public class EnumBinaryCodec : IBinaryCodec where E : Enum + { + private readonly Array entries = Enum.GetValues(typeof(E)); + + public void Write(IByteBuffer buffer, E value) + { + var ordinal = Array.IndexOf(entries, value); + if (ordinal < 0) + { + throw new ArgumentOutOfRangeException( + nameof(value), + value, + $"Value is not defined for enum {typeof(E).Name}."); + } + + BinaryCodecs.VAR_INT.Write(buffer, ordinal); + } + + public E Read(IByteBuffer buffer) + { + var ordinal = BinaryCodecs.VAR_INT.Read(buffer); + if (ordinal < 0 || ordinal >= entries.Length) throw new IndexOutOfRangeException($"Ordinal {ordinal} is outside the range [0, {entries.Length - 1}] for enum {typeof(E).Name}"); + + return (E)entries.GetValue(ordinal)!; + } + } + + public class BinaryCodecEmpty( + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + } + + public Result Read(IByteBuffer buffer) + { + return func.Invoke(); + } + } + + public class BinaryCodecP1( + IBinaryCodec codec1, + Func getter1, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + return func.Invoke(result1); + } + } + + public class BinaryCodecP2( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + return func.Invoke(result1, result2); + } + } + + public class BinaryCodecP3( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + return func.Invoke(result1, result2, result3); + } + } + + public class BinaryCodecP4( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + return func.Invoke(result1, result2, result3, result4); + } + } + + public class BinaryCodecP5( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5); + } + } + + public class BinaryCodecP6( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + IBinaryCodec codec6, + Func getter6, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + codec6.Write(buffer, getter6.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + var result6 = codec6.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5, result6); + } + } + + public class BinaryCodecP7( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + IBinaryCodec codec6, + Func getter6, + IBinaryCodec codec7, + Func getter7, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + codec6.Write(buffer, getter6.Invoke(value)); + codec7.Write(buffer, getter7.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + var result6 = codec6.Read(buffer); + var result7 = codec7.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5, result6, result7); + } + } + + public class BinaryCodecP8( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + IBinaryCodec codec6, + Func getter6, + IBinaryCodec codec7, + Func getter7, + IBinaryCodec codec8, + Func getter8, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + codec6.Write(buffer, getter6.Invoke(value)); + codec7.Write(buffer, getter7.Invoke(value)); + codec8.Write(buffer, getter8.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + var result6 = codec6.Read(buffer); + var result7 = codec7.Read(buffer); + var result8 = codec8.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8); + } + } + + public class BinaryCodecP9( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + IBinaryCodec codec6, + Func getter6, + IBinaryCodec codec7, + Func getter7, + IBinaryCodec codec8, + Func getter8, + IBinaryCodec codec9, + Func getter9, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + codec6.Write(buffer, getter6.Invoke(value)); + codec7.Write(buffer, getter7.Invoke(value)); + codec8.Write(buffer, getter8.Invoke(value)); + codec9.Write(buffer, getter9.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + var result6 = codec6.Read(buffer); + var result7 = codec7.Read(buffer); + var result8 = codec8.Read(buffer); + var result9 = codec9.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9); + } + } + + public class BinaryCodecP10( + IBinaryCodec codec1, + Func getter1, + IBinaryCodec codec2, + Func getter2, + IBinaryCodec codec3, + Func getter3, + IBinaryCodec codec4, + Func getter4, + IBinaryCodec codec5, + Func getter5, + IBinaryCodec codec6, + Func getter6, + IBinaryCodec codec7, + Func getter7, + IBinaryCodec codec8, + Func getter8, + IBinaryCodec codec9, + Func getter9, + IBinaryCodec codec10, + Func getter10, + Func func + ) : IBinaryCodec + { + public void Write(IByteBuffer buffer, Result value) + { + codec1.Write(buffer, getter1.Invoke(value)); + codec2.Write(buffer, getter2.Invoke(value)); + codec3.Write(buffer, getter3.Invoke(value)); + codec4.Write(buffer, getter4.Invoke(value)); + codec5.Write(buffer, getter5.Invoke(value)); + codec6.Write(buffer, getter6.Invoke(value)); + codec7.Write(buffer, getter7.Invoke(value)); + codec8.Write(buffer, getter8.Invoke(value)); + codec9.Write(buffer, getter9.Invoke(value)); + codec10.Write(buffer, getter10.Invoke(value)); + } + + public Result Read(IByteBuffer buffer) + { + var result1 = codec1.Read(buffer); + var result2 = codec2.Read(buffer); + var result3 = codec3.Read(buffer); + var result4 = codec4.Read(buffer); + var result5 = codec5.Read(buffer); + var result6 = codec6.Read(buffer); + var result7 = codec7.Read(buffer); + var result8 = codec8.Read(buffer); + var result9 = codec9.Read(buffer); + var result10 = codec10.Read(buffer); + return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10); + } + } +} diff --git a/Codon.BinaryCodec/BinaryCodecs.cs b/Codon.BinaryCodec/BinaryCodecs.cs index c430cd1..9f4870d 100644 --- a/Codon.BinaryCodec/BinaryCodecs.cs +++ b/Codon.BinaryCodec/BinaryCodecs.cs @@ -1,1181 +1,89 @@ +// Copyright (c) 2026 SynesthesiaDev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Codon.Optionals; +using System.Runtime.CompilerServices; using DotNetty.Buffers; +#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. namespace Codon.Binary; public static class BinaryCodecs { - public class BooleanBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, bool value) - { - buffer.WriteBoolean(value); - } + public static readonly IBinaryCodec BOOLEAN = new BinaryCodecDefinitions.BooleanBinaryCodec(); - public bool Read(IByteBuffer buffer) - { - return buffer.ReadBoolean(); - } - } - - public class ByteBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, byte value) - { - buffer.WriteByte(value); - } + public static readonly IBinaryCodec BYTE = new BinaryCodecDefinitions.ByteBinaryCodec(); - public byte Read(IByteBuffer buffer) - { - return buffer.ReadByte(); - } - } + public static readonly IBinaryCodec INT = new BinaryCodecDefinitions.IntBinaryCodec(); - public class IntBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, int value) - { - buffer.WriteInt(value); - } + public static readonly IBinaryCodec LONG = new BinaryCodecDefinitions.LongBinaryCodec(); - public int Read(IByteBuffer buffer) - { - return buffer.ReadInt(); - } - } + public static readonly IBinaryCodec DOUBLE = new BinaryCodecDefinitions.DoubleBinaryCodec(); - public class LongBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, long value) - { - buffer.WriteLong(value); - } + public static readonly IBinaryCodec FLOAT = new BinaryCodecDefinitions.FloatBinaryCodec(); - public long Read(IByteBuffer buffer) - { - return buffer.ReadLong(); - } - } + public static readonly IBinaryCodec VAR_INT = new BinaryCodecDefinitions.VarIntBinaryCodec(); - public class FloatBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, float value) - { - buffer.WriteFloat(value); - } - - public float Read(IByteBuffer buffer) - { - return buffer.ReadFloat(); - } - } - - public class DoubleBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, double value) - { - buffer.WriteDouble(value); - } - - public double Read(IByteBuffer buffer) - { - return buffer.ReadDouble(); - } - } - - public class VarIntBinaryCodec : BinaryCodec - { - private const int segment_bits = 0x7F; - private const int continue_bit = 0x80; + public static readonly IBinaryCodec BYTE_ARRAY = new BinaryCodecDefinitions.ByteArrayBinaryCodec(); - public void Write(IByteBuffer buffer, int value) - { - var uValue = (uint)value; - while (true) - { - if ((uValue & ~segment_bits) == 0) - { - buffer.WriteByte((byte)uValue); - break; - } + public static readonly IBinaryCodec BYTE_BUFFER = new BinaryCodecDefinitions.ByteBufferBinaryCodec(); - buffer.WriteByte((byte)((uValue & segment_bits) | continue_bit)); + public static readonly IBinaryCodec RAW_BYTES = new BinaryCodecDefinitions.RawBytesBinaryCodec(); - uValue >>= 7; - } - } + public static readonly IBinaryCodec STRING = new BinaryCodecDefinitions.StringBinaryCodec(); - public int Read(IByteBuffer buffer) - { - var value = 0; - var position = 0; + public static readonly IBinaryCodec GUID = BYTE_ARRAY.Transform(guid => guid.ToByteArray(), bytes => new Guid(bytes)); - while (position < 35) // Max 5 bytes - { - var currentByte = buffer.ReadByte(); - var segment = currentByte & segment_bits; + public static BinaryCodecDefinitions.RecursiveBinaryCodec Recursive(Func, IBinaryCodec> self) where T : notnull => new(self); - value |= segment << position; + public static IBinaryCodec ByteArray(int? maxSize = null) => new BinaryCodecDefinitions.ByteArrayBinaryCodec(maxSize); - // finished reading - if ((currentByte & continue_bit) == 0) return value; - - position += 7; - } - - throw new InvalidDataException("VarInt is too long"); - } - } - - public class ByteArrayBinaryCodec(int? maxSize = null) : BinaryCodec - { - public void Write(IByteBuffer buffer, byte[] value) - { - if (maxSize != null && value.Length > maxSize) - throw new ArgumentException($"The byte array is longer than maximum allowed ({value.Length} > {maxSize})", nameof(value)); - - BinaryCodec.VAR_INT.Write(buffer, value.Length); - buffer.WriteBytes(value); - } - - public byte[] Read(IByteBuffer buffer) - { - var size = BinaryCodec.VAR_INT.Read(buffer); - return size > maxSize ? throw new InvalidDataException($"The read byte array is longer than maximum allowed (${size} > {maxSize}") : buffer.ToByteArraySafe(size); - } - } - - public class ByteBufferBinaryCodec(int? maxSize = null) : BinaryCodec - { - public void Write(IByteBuffer buffer, IByteBuffer value) - { - var size = value.ReadableBytes; - - if (maxSize is not null && size > maxSize.Value) - { - throw new ArgumentException( - $"The byte buffer is longer than maximum allowed ({size} > {maxSize.Value})", - nameof(value)); - } - - BinaryCodec.VAR_INT.Write(buffer, size); - buffer.WriteBytes(value, value.ReaderIndex, size); - } - - public IByteBuffer Read(IByteBuffer buffer) - { - var size = BinaryCodec.VAR_INT.Read(buffer); - - if (size < 0) - throw new InvalidDataException($"Size cannot be negative."); - - - if (size > maxSize) - throw new InvalidDataException($"The read byte buffer is longer than maximum allowed (${size} > {maxSize}"); - - return buffer.ReadBytes(size); - } - } + public static IBinaryCodec ByteBuffer(int? maxSize = null) => new BinaryCodecDefinitions.ByteBufferBinaryCodec(maxSize); - public class StringBinaryCodec(int? maxStringLength = null) : BinaryCodec - { - public void Write(IByteBuffer buffer, string value) - { - var stringBytes = Encoding.UTF8.GetBytes(value); - - if (maxStringLength is not null && stringBytes.Length > maxStringLength.Value) - throw new ArgumentException($"String is longer than maximum allowed ({stringBytes.Length} > {maxStringLength.Value})", nameof(value)); - - BinaryCodec.VAR_INT.Write(buffer, stringBytes.Length); - buffer.WriteBytes(stringBytes); - } - - public string Read(IByteBuffer buffer) - { - var size = BinaryCodec.VAR_INT.Read(buffer); - - if (size < 0) - throw new InvalidDataException($"The read string has negative length: {size}"); - - if (maxStringLength is not null && size > maxStringLength.Value) - throw new InvalidDataException($"Read string is longer than maximum allowed ({size} > {maxStringLength.Value})"); - - var stringBytes = buffer.ToByteArraySafe(size); - return Encoding.UTF8.GetString(stringBytes); - } - } - - public class RawBytesBinaryCodec : BinaryCodec - { - public void Write(IByteBuffer buffer, byte[] value) - { - buffer.WriteBytes(value); - } - - public byte[] Read(IByteBuffer buffer) - { - return buffer.ToByteArraySafe(); - } - } - - public class OptionalBinaryCodec(BinaryCodec innerCodec) : BinaryCodec> - { - public void Write(IByteBuffer buffer, Optional value) - { - BinaryCodec.BOOLEAN.Write(buffer, value.IsPresent); - if (value.IsPresent) innerCodec.Write(buffer, value.Value!); - } - - public Optional Read(IByteBuffer buffer) - { - return BinaryCodec.BOOLEAN.Read(buffer) ? Optional.Of(innerCodec.Read(buffer)) : Optional.Empty(); - } - } - - public class DefaultBinaryCodec(BinaryCodec innerCodec, T defaultValue) : BinaryCodec where T : notnull - { - public void Write(IByteBuffer buffer, T? value) - { - BinaryCodec.BOOLEAN.Write(buffer, value != null); - innerCodec.Write(buffer, value ?? defaultValue); - } - - public T Read(IByteBuffer buffer) - { - return BinaryCodec.BOOLEAN.Read(buffer) ? innerCodec.Read(buffer) : defaultValue; - } - } - - public class TransformativeBinaryCodec(BinaryCodec innerCodec, Func from, Func to) : BinaryCodec where S : notnull where T : notnull - { - public void Write(IByteBuffer buffer, S value) - { - innerCodec.Write(buffer, from.Invoke(value)); - } - - public S Read(IByteBuffer buffer) - { - var innerValue = innerCodec.Read(buffer); - return to.Invoke(innerValue); - } - } - - public class DictionaryBinaryCodec(BinaryCodec keyCodec, BinaryCodec valueCodec, int? maxSize = null) : BinaryCodec> where K : notnull where V : notnull - { - public void Write(IByteBuffer buffer, Dictionary value) - { - - if (maxSize != null && value.Count > maxSize) - throw new ArgumentException($"There are more map entries than maximum allowed ({value.Count} > {maxSize})", nameof(value)); - - BinaryCodec.VAR_INT.Write(buffer, value.Count); - foreach (var keyValuePair in value) - { - keyCodec.Write(buffer, keyValuePair.Key); - valueCodec.Write(buffer, keyValuePair.Value); - } - } - - public Dictionary Read(IByteBuffer buffer) - { - var dict = new Dictionary(); - var size = BinaryCodec.VAR_INT.Read(buffer); // how big is my dic(t)... - - if (size < 0) - throw new InvalidDataException($"The read dictionary has negative entry count: {size}"); - - if (maxSize != null && size > maxSize) - throw new InvalidDataException($"The read dictionary has more entries than maximum allowed ({size} > {maxSize})"); - - for (var i = 0; i < size; i++) - { - var key = keyCodec.Read(buffer); - var value = valueCodec.Read(buffer); - dict[key] = value; - } - - return dict; - } - } - - public class ListBinaryCodec(BinaryCodec innerCodec, int? maxSize = null) : BinaryCodec> - { - public void Write(IByteBuffer buffer, List value) - { - if (maxSize != null && value.Count > maxSize) - throw new ArgumentException($"There are more list entries than maximum allowed ({value.Count} > {maxSize})", nameof(value)); + public static BinaryCodecDefinitions.EnumBinaryCodec Enum() where E : Enum => new(); - BinaryCodec.VAR_INT.Write(buffer, value.Count); - value.ForEach(item => innerCodec.Write(buffer, item)); - } + public static IBinaryCodec Flags() where Te : struct, Enum => BYTE.Transform(te => Unsafe.As(ref te), by => Unsafe.As(ref by)); - public List Read(IByteBuffer buffer) - { - var list = new List(); - var size = BinaryCodec.VAR_INT.Read(buffer); + public static IBinaryCodec String(int maxLength) => new BinaryCodecDefinitions.StringBinaryCodec(maxLength); - if (size < 0) - throw new InvalidDataException($"The read list has negative entry count: {size}"); + public static IBinaryCodec Empty(Func func) => new BinaryCodecDefinitions.BinaryCodecEmpty(func); - if (size > maxSize) - throw new InvalidDataException($"The read list has more entries than maximum allowed ({size} > {maxSize})"); - - for (var i = 0; i < size; i++) list.Add(innerCodec.Read(buffer)); - - return list; - } - } - - public class UnionBinaryCodec(BinaryCodec keyCodec, Func keyFunc, Func> serializerFactory) : BinaryCodec - { - public void Write(IByteBuffer buffer, T value) - { - var key = keyFunc.Invoke(value); - keyCodec.Write(buffer, key); - - var serializer = serializerFactory.Invoke(key); - serializer.Write(buffer, value); - } - - public T Read(IByteBuffer buffer) - { - var key = keyCodec.Read(buffer); - var serializer = serializerFactory.Invoke(key); - return serializer.Read(buffer); - } - } - - public class RecursiveBinaryCodec : BinaryCodec where T : notnull - { - private readonly Lazy> @delegate; - - public RecursiveBinaryCodec(Func, BinaryCodec> self) - { - @delegate = new Lazy>(() => self.Invoke(this)); - } - - public void Write(IByteBuffer buffer, T value) - { - @delegate.Value.Write(buffer, value); - } - - public T Read(IByteBuffer buffer) - { - return @delegate.Value.Read(buffer); - } - } - - public class EnumBinaryCodec : BinaryCodec where E : Enum - { - private readonly Array entries = Enum.GetValues(typeof(E)); - - public void Write(IByteBuffer buffer, E value) - { - var ordinal = Array.IndexOf(entries, value); - if (ordinal < 0) - { - throw new ArgumentOutOfRangeException( - nameof(value), - value, - $"Value is not defined for enum {typeof(E).Name}."); - } - - BinaryCodec.VAR_INT.Write(buffer, ordinal); - } - - public E Read(IByteBuffer buffer) - { - var ordinal = BinaryCodec.VAR_INT.Read(buffer); - if (ordinal < 0 || ordinal >= entries.Length) throw new IndexOutOfRangeException($"Ordinal {ordinal} is outside the range [0, {entries.Length - 1}] for enum {typeof(E).Name}"); - - return (E)entries.GetValue(ordinal)!; - } - } - - public class BinaryCodecEmpty( - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - } - - public Result Read(IByteBuffer buffer) - { - return func.Invoke(); - } - } - - public class BinaryCodecP1( - BinaryCodec codec1, - Func getter1, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - return func.Invoke(result1); - } - } - - public class BinaryCodecP2( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - return func.Invoke(result1, result2); - } - } - - public class BinaryCodecP3( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - return func.Invoke(result1, result2, result3); - } - } - - public class BinaryCodecP4( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - return func.Invoke(result1, result2, result3, result4); - } - } - - public class BinaryCodecP5( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5); - } - } - - public class BinaryCodecP6( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6); - } - } - - public class BinaryCodecP7( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7); - } - } - - public class BinaryCodecP8( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8); - } - } - - public class BinaryCodecP9( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9); - } - } - - public class BinaryCodecP10( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - Func func - ) : BinaryCodec - { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - } + public static BinaryCodecBuilder For() => new(); +} - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10); - } - } +public interface IBinaryCodec +{ + void Write(IByteBuffer buffer, T value); + T Read(IByteBuffer buffer); - public class BinaryCodecP11( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.OptionalBinaryCodec Optional() { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11); - } + return new BinaryCodecDefinitions.OptionalBinaryCodec(this); } - public class BinaryCodecP12( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - BinaryCodec codec12, - Func getter12, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.DefaultBinaryCodec Default(T defaultValue) { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - codec12.Write(buffer, getter12.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - var result12 = codec12.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12); - } + return new BinaryCodecDefinitions.DefaultBinaryCodec(this, defaultValue); } - public class BinaryCodecP13( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - BinaryCodec codec12, - Func getter12, - BinaryCodec codec13, - Func getter13, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.TransformativeBinaryCodec Transform(Func from, Func to) { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - codec12.Write(buffer, getter12.Invoke(value)); - codec13.Write(buffer, getter13.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - var result12 = codec12.Read(buffer); - var result13 = codec13.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13); - } + return new BinaryCodecDefinitions.TransformativeBinaryCodec(this, from, to); } - public class BinaryCodecP14( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - BinaryCodec codec12, - Func getter12, - BinaryCodec codec13, - Func getter13, - BinaryCodec codec14, - Func getter14, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.DictionaryBinaryCodec MapTo(IBinaryCodec valueCodec, int? maxSize = null) where V : notnull { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - codec12.Write(buffer, getter12.Invoke(value)); - codec13.Write(buffer, getter13.Invoke(value)); - codec14.Write(buffer, getter14.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - var result12 = codec12.Read(buffer); - var result13 = codec13.Read(buffer); - var result14 = codec14.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14); - } + return new BinaryCodecDefinitions.DictionaryBinaryCodec(this, valueCodec, maxSize); } - public class BinaryCodecP15( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - BinaryCodec codec12, - Func getter12, - BinaryCodec codec13, - Func getter13, - BinaryCodec codec14, - Func getter14, - BinaryCodec codec15, - Func getter15, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.ListBinaryCodec List(int? maxSize = null) { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - codec12.Write(buffer, getter12.Invoke(value)); - codec13.Write(buffer, getter13.Invoke(value)); - codec14.Write(buffer, getter14.Invoke(value)); - codec15.Write(buffer, getter15.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - var result12 = codec12.Read(buffer); - var result13 = codec13.Read(buffer); - var result14 = codec14.Read(buffer); - var result15 = codec15.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15); - } + return new BinaryCodecDefinitions.ListBinaryCodec(this, maxSize); } - public class BinaryCodecP16( - BinaryCodec codec1, - Func getter1, - BinaryCodec codec2, - Func getter2, - BinaryCodec codec3, - Func getter3, - BinaryCodec codec4, - Func getter4, - BinaryCodec codec5, - Func getter5, - BinaryCodec codec6, - Func getter6, - BinaryCodec codec7, - Func getter7, - BinaryCodec codec8, - Func getter8, - BinaryCodec codec9, - Func getter9, - BinaryCodec codec10, - Func getter10, - BinaryCodec codec11, - Func getter11, - BinaryCodec codec12, - Func getter12, - BinaryCodec codec13, - Func getter13, - BinaryCodec codec14, - Func getter14, - BinaryCodec codec15, - Func getter15, - BinaryCodec codec16, - Func getter16, - Func func - ) : BinaryCodec + BinaryCodecDefinitions.UnionBinaryCodec Union(Func> serializerFactory, Func keyFunc) where K : notnull { - public void Write(IByteBuffer buffer, Result value) - { - codec1.Write(buffer, getter1.Invoke(value)); - codec2.Write(buffer, getter2.Invoke(value)); - codec3.Write(buffer, getter3.Invoke(value)); - codec4.Write(buffer, getter4.Invoke(value)); - codec5.Write(buffer, getter5.Invoke(value)); - codec6.Write(buffer, getter6.Invoke(value)); - codec7.Write(buffer, getter7.Invoke(value)); - codec8.Write(buffer, getter8.Invoke(value)); - codec9.Write(buffer, getter9.Invoke(value)); - codec10.Write(buffer, getter10.Invoke(value)); - codec11.Write(buffer, getter11.Invoke(value)); - codec12.Write(buffer, getter12.Invoke(value)); - codec13.Write(buffer, getter13.Invoke(value)); - codec14.Write(buffer, getter14.Invoke(value)); - codec15.Write(buffer, getter15.Invoke(value)); - codec16.Write(buffer, getter16.Invoke(value)); - } - - public Result Read(IByteBuffer buffer) - { - var result1 = codec1.Read(buffer); - var result2 = codec2.Read(buffer); - var result3 = codec3.Read(buffer); - var result4 = codec4.Read(buffer); - var result5 = codec5.Read(buffer); - var result6 = codec6.Read(buffer); - var result7 = codec7.Read(buffer); - var result8 = codec8.Read(buffer); - var result9 = codec9.Read(buffer); - var result10 = codec10.Read(buffer); - var result11 = codec11.Read(buffer); - var result12 = codec12.Read(buffer); - var result13 = codec13.Read(buffer); - var result14 = codec14.Read(buffer); - var result15 = codec15.Read(buffer); - var result16 = codec16.Read(buffer); - return func.Invoke(result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12, result13, result14, result15, result16); - } + return new BinaryCodecDefinitions.UnionBinaryCodec(this, keyFunc, serializerFactory); } } diff --git a/Codon.Tests/BinaryCodecTests.cs b/Codon.Tests/BinaryCodecsTests.cs similarity index 63% rename from Codon.Tests/BinaryCodecTests.cs rename to Codon.Tests/BinaryCodecsTests.cs index 8e7c722..e959dc3 100644 --- a/Codon.Tests/BinaryCodecTests.cs +++ b/Codon.Tests/BinaryCodecsTests.cs @@ -4,9 +4,9 @@ namespace Codon.Tests; -public class BinaryCodecTests +public class BinaryCodecsTests { - private static T roundTrip(BinaryCodec codec, T value) + private static T roundTrip(IBinaryCodec codec, T value) { var buf = Unpooled.Buffer(); codec.Write(buf, value!); @@ -15,7 +15,7 @@ private static T roundTrip(BinaryCodec codec, T value) private record VeryEmptyClass { - public static readonly BinaryCodec CODEC = BinaryCodec.Empty(() => new VeryEmptyClass()); + public static readonly IBinaryCodec CODEC = BinaryCodecs.Empty(() => new VeryEmptyClass()); } [Test] @@ -31,22 +31,22 @@ public void TestEmptyCodec() [Test] public void PrimitiveCodecs_RoundTrip() { - Assert.That(roundTrip(BinaryCodec.BOOLEAN, true), Is.True); - Assert.That(roundTrip(BinaryCodec.BOOLEAN, false), Is.False); + Assert.That(roundTrip(BinaryCodecs.BOOLEAN, true), Is.True); + Assert.That(roundTrip(BinaryCodecs.BOOLEAN, false), Is.False); - Assert.That(roundTrip(BinaryCodec.BYTE, (byte)0), Is.EqualTo((byte)0)); - Assert.That(roundTrip(BinaryCodec.BYTE, (byte)255), Is.EqualTo((byte)255)); + Assert.That(roundTrip(BinaryCodecs.BYTE, (byte)0), Is.EqualTo((byte)0)); + Assert.That(roundTrip(BinaryCodecs.BYTE, (byte)255), Is.EqualTo((byte)255)); - Assert.That(roundTrip(BinaryCodec.INT, 0), Is.EqualTo(0)); - Assert.That(roundTrip(BinaryCodec.INT, 123456789), Is.EqualTo(123456789)); - Assert.That(roundTrip(BinaryCodec.INT, -123456789), Is.EqualTo(-123456789)); + Assert.That(roundTrip(BinaryCodecs.INT, 0), Is.EqualTo(0)); + Assert.That(roundTrip(BinaryCodecs.INT, 123456789), Is.EqualTo(123456789)); + Assert.That(roundTrip(BinaryCodecs.INT, -123456789), Is.EqualTo(-123456789)); - Assert.That(roundTrip(BinaryCodec.LONG, 0L), Is.EqualTo(0L)); - Assert.That(roundTrip(BinaryCodec.LONG, long.MaxValue), Is.EqualTo(long.MaxValue)); - Assert.That(roundTrip(BinaryCodec.LONG, long.MinValue), Is.EqualTo(long.MinValue)); + Assert.That(roundTrip(BinaryCodecs.LONG, 0L), Is.EqualTo(0L)); + Assert.That(roundTrip(BinaryCodecs.LONG, long.MaxValue), Is.EqualTo(long.MaxValue)); + Assert.That(roundTrip(BinaryCodecs.LONG, long.MinValue), Is.EqualTo(long.MinValue)); - Assert.That(roundTrip(BinaryCodec.FLOAT, 123.456f), Is.EqualTo(123.456f)); - Assert.That(roundTrip(BinaryCodec.DOUBLE, -123.456789), Is.EqualTo(-123.456789)); + Assert.That(roundTrip(BinaryCodecs.FLOAT, 123.456f), Is.EqualTo(123.456f)); + Assert.That(roundTrip(BinaryCodecs.DOUBLE, -123.456789), Is.EqualTo(-123.456789)); } [Test] @@ -56,8 +56,8 @@ public void VarInt_RoundTrip_WithEdgeCases() foreach (var v in values) { var buf = Unpooled.Buffer(); - BinaryCodec.VAR_INT.Write(buf, v); - var read = BinaryCodec.VAR_INT.Read(buf); + BinaryCodecs.VAR_INT.Write(buf, v); + var read = BinaryCodecs.VAR_INT.Read(buf); Assert.That(read, Is.EqualTo(v), $"VarInt roundtrip failed for {v}"); } } @@ -67,8 +67,8 @@ public void Guid_RoundTrip() { var guid = Guid.NewGuid(); var buf = Unpooled.Buffer(); - BinaryCodec.GUID.Write(buf, guid); - var read = BinaryCodec.GUID.Read(buf); + BinaryCodecs.GUID.Write(buf, guid); + var read = BinaryCodecs.GUID.Read(buf); Assert.That(read, Is.EqualTo(guid)); } @@ -77,8 +77,8 @@ public void Flags_RoundTrip() { const FlagsTest flags = FlagsTest.SoCool & FlagsTest.Gay; var buf = Unpooled.Buffer(); - BinaryCodec.Flags().Write(buf, flags); - var read = BinaryCodec.Flags().Read(buf); + BinaryCodecs.Flags().Write(buf, flags); + var read = BinaryCodecs.Flags().Read(buf); Assert.That(read, Is.EqualTo(flags)); } @@ -98,14 +98,14 @@ enum FlagsTest public void ByteArray_And_RawBytes_RoundTrip() { var empty = Array.Empty(); - Assert.That(roundTrip(BinaryCodec.BYTE_ARRAY, empty), Is.EqualTo(empty)); + Assert.That(roundTrip(BinaryCodecs.BYTE_ARRAY, empty), Is.EqualTo(empty)); var data = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray(); - Assert.That(roundTrip(BinaryCodec.BYTE_ARRAY, data), Is.EqualTo(data)); + Assert.That(roundTrip(BinaryCodecs.BYTE_ARRAY, data), Is.EqualTo(data)); var buf = Unpooled.Buffer(); - BinaryCodec.RAW_BYTES.Write(buf, data); - var read = BinaryCodec.RAW_BYTES.Read(buf); + BinaryCodecs.RAW_BYTES.Write(buf, data); + var read = BinaryCodecs.RAW_BYTES.Read(buf); Assert.That(read, Is.EqualTo(data)); } @@ -117,8 +117,8 @@ public void BinaryBuffer_Codec_RoundTrip() original.WriteInt(42); var buf = Unpooled.Buffer(); - BinaryCodec.BYTE_BUFFER.Write(buf, original); - var round = BinaryCodec.BYTE_BUFFER.Read(buf); + BinaryCodecs.BYTE_BUFFER.Write(buf, original); + var round = BinaryCodecs.BYTE_BUFFER.Read(buf); Assert.That(round.ReadableBytes, Is.EqualTo(original.ReadableBytes)); @@ -133,16 +133,16 @@ public void BinaryBuffer_Codec_RoundTrip() [Test] public void String_Codec_RoundTrip() { - Assert.That(roundTrip(BinaryCodec.STRING, string.Empty), Is.EqualTo(string.Empty)); - Assert.That(roundTrip(BinaryCodec.STRING, "ascii"), Is.EqualTo("ascii")); + Assert.That(roundTrip(BinaryCodecs.STRING, string.Empty), Is.EqualTo(string.Empty)); + Assert.That(roundTrip(BinaryCodecs.STRING, "ascii"), Is.EqualTo("ascii")); var unicode = "你好世界 👋🌍"; - Assert.That(roundTrip(BinaryCodec.STRING, unicode), Is.EqualTo(unicode)); + Assert.That(roundTrip(BinaryCodecs.STRING, unicode), Is.EqualTo(unicode)); } [Test] public void Optional_Codec_WritesPresenceAndValue() { - var optionalInt = BinaryCodec.INT.Optional(); + var optionalInt = BinaryCodecs.INT.Optional(); var some = Optional.Of(123); var bufSome = Unpooled.Buffer(); @@ -168,7 +168,7 @@ private enum TestEnum [Test] public void Enum_Codec_UsesOrdinal() { - var codec = BinaryCodec.Enum(); + var codec = BinaryCodecs.Enum(); Assert.That(roundTrip(codec, TestEnum.A), Is.EqualTo(TestEnum.A)); Assert.That(roundTrip(codec, TestEnum.B), Is.EqualTo(TestEnum.B)); Assert.That(roundTrip(codec, TestEnum.C), Is.EqualTo(TestEnum.C)); @@ -177,7 +177,7 @@ public void Enum_Codec_UsesOrdinal() [Test] public void Transformative_Codec_RoundTrip() { - var codec = BinaryCodec.INT.Transform( + var codec = BinaryCodecs.INT.Transform( from: s => s.Length, to: n => new string('x', n) ); @@ -192,12 +192,12 @@ public void Transformative_Codec_RoundTrip() [Test] public void List_And_Dictionary_Codecs_RoundTrip() { - BinaryCodecs.ListBinaryCodec listCodec = BinaryCodec.STRING.List(); + BinaryCodecDefinitions.ListBinaryCodec listCodec = BinaryCodecs.STRING.List(); var list = new List { "a", "b", "c" }; Assert.That(roundTrip(listCodec, list), Is.EqualTo(list)); - var mapCodec = BinaryCodec.INT.MapTo(BinaryCodec.STRING); + var mapCodec = BinaryCodecs.INT.MapTo(BinaryCodecs.STRING); var dict = new Dictionary { { 1, "one" }, { 2, "two" }, { 3, "three" } }; var round = roundTrip(mapCodec, dict); Assert.That(round, Has.Count.EqualTo(3)); @@ -207,10 +207,10 @@ public void List_And_Dictionary_Codecs_RoundTrip() [Test] public void Union_Codec_RoundTrip_WithInt_KeyByte() { - var union = new BinaryCodecs.UnionBinaryCodec( - keyCodec: BinaryCodec.BYTE, + var union = new BinaryCodecDefinitions.UnionBinaryCodec( + keyCodec: BinaryCodecs.BYTE, keyFunc: v => (byte)(v % 2), - serializerFactory: _ => BinaryCodec.INT + serializerFactory: _ => BinaryCodecs.INT ); var round = roundTrip(union, 7); @@ -222,12 +222,11 @@ public record Person(string Name, int Age, bool Active); [Test] public void Composite_Codec_P3_RoundTrip() { - var personCodec = BinaryCodec.Of( - BinaryCodec.STRING, p => p.Name, - BinaryCodec.INT, p => p.Age, - BinaryCodec.BOOLEAN, p => p.Active, - (name, age, active) => new Person(name, age, active) - ); + var personCodec = BinaryCodecs.For() + .Field(BinaryCodecs.STRING, p => p.Name) + .Field(BinaryCodecs.INT, p => p.Age) + .Field(BinaryCodecs.BOOLEAN, p => p.Active) + .Build((name, age, active) => new Person(name, age, active)); var p = new Person("Alice", 30, true); Assert.That(roundTrip(personCodec, p), Is.EqualTo(p)); @@ -235,13 +234,11 @@ public void Composite_Codec_P3_RoundTrip() public record Node(string Name, List Children) { - public static readonly BinaryCodec CODEC = BinaryCodec.Recursive(self => - BinaryCodec.Of( - BinaryCodec.STRING, n => n.Name, - self.List(), n => n.Children, - (name, children) => new Node(name, children) - ) - ); + public static readonly IBinaryCodec CODEC = BinaryCodecs.Recursive(self => + BinaryCodecs.For() + .Field(BinaryCodecs.STRING, n => n.Name) + .Field(self.List(), n => n.Children) + .Build((name, children) => new Node(name, children))); } [Test]