| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| using System.Collections.Immutable; |
| |
| namespace Apache.Fory; |
| |
| internal static class PrimitiveCollectionHeader |
| { |
| public static void WriteListHeader(WriteContext context, int count, bool hasGenerics, TypeId elementTypeId, bool hasNull) |
| { |
| context.Writer.WriteVarUInt32((uint)count); |
| if (count == 0) |
| { |
| return; |
| } |
| |
| bool declared = hasGenerics && !TypeResolver.NeedToWriteTypeInfoForField(elementTypeId); |
| byte header = CollectionBits.SameType; |
| if (hasNull) |
| { |
| header |= CollectionBits.HasNull; |
| } |
| |
| if (declared) |
| { |
| header |= CollectionBits.DeclaredElementType; |
| } |
| |
| context.Writer.WriteUInt8(header); |
| if (!declared) |
| { |
| context.Writer.WriteUInt8((byte)elementTypeId); |
| } |
| } |
| } |
| |
| internal sealed class ListBoolSerializer : Serializer<List<bool>> |
| { |
| private static readonly ListSerializer<bool> Fallback = new(); |
| |
| |
| |
| |
| public override List<bool> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<bool> value, bool hasGenerics) |
| { |
| List<bool> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.Bool, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteUInt8(list[i] ? (byte)1 : (byte)0); |
| } |
| } |
| |
| public override List<bool> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListInt8Serializer : Serializer<List<sbyte>> |
| { |
| private static readonly ListSerializer<sbyte> Fallback = new(); |
| |
| |
| |
| |
| public override List<sbyte> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<sbyte> value, bool hasGenerics) |
| { |
| List<sbyte> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.Int8, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteInt8(list[i]); |
| } |
| } |
| |
| public override List<sbyte> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListInt16Serializer : Serializer<List<short>> |
| { |
| private static readonly ListSerializer<short> Fallback = new(); |
| |
| |
| |
| |
| public override List<short> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<short> value, bool hasGenerics) |
| { |
| List<short> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.Int16, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteInt16(list[i]); |
| } |
| } |
| |
| public override List<short> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListIntSerializer : Serializer<List<int>> |
| { |
| private static readonly ListSerializer<int> Fallback = new(); |
| |
| |
| |
| |
| public override List<int> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<int> value, bool hasGenerics) |
| { |
| List<int> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.VarInt32, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteVarInt32(list[i]); |
| } |
| } |
| |
| public override List<int> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListLongSerializer : Serializer<List<long>> |
| { |
| private static readonly ListSerializer<long> Fallback = new(); |
| |
| |
| |
| |
| public override List<long> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<long> value, bool hasGenerics) |
| { |
| List<long> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.VarInt64, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteVarInt64(list[i]); |
| } |
| } |
| |
| public override List<long> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListUInt8Serializer : Serializer<List<byte>> |
| { |
| private static readonly ListSerializer<byte> Fallback = new(); |
| |
| |
| |
| |
| public override List<byte> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<byte> value, bool hasGenerics) |
| { |
| List<byte> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.UInt8, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteUInt8(list[i]); |
| } |
| } |
| |
| public override List<byte> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListUInt16Serializer : Serializer<List<ushort>> |
| { |
| private static readonly ListSerializer<ushort> Fallback = new(); |
| |
| |
| |
| |
| public override List<ushort> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<ushort> value, bool hasGenerics) |
| { |
| List<ushort> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.UInt16, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteUInt16(list[i]); |
| } |
| } |
| |
| public override List<ushort> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListUIntSerializer : Serializer<List<uint>> |
| { |
| private static readonly ListSerializer<uint> Fallback = new(); |
| |
| |
| |
| |
| public override List<uint> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<uint> value, bool hasGenerics) |
| { |
| List<uint> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.VarUInt32, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteVarUInt32(list[i]); |
| } |
| } |
| |
| public override List<uint> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListULongSerializer : Serializer<List<ulong>> |
| { |
| private static readonly ListSerializer<ulong> Fallback = new(); |
| |
| |
| |
| |
| public override List<ulong> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<ulong> value, bool hasGenerics) |
| { |
| List<ulong> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.VarUInt64, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteVarUInt64(list[i]); |
| } |
| } |
| |
| public override List<ulong> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListFloatSerializer : Serializer<List<float>> |
| { |
| private static readonly ListSerializer<float> Fallback = new(); |
| |
| |
| |
| |
| public override List<float> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<float> value, bool hasGenerics) |
| { |
| List<float> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.Float32, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteFloat32(list[i]); |
| } |
| } |
| |
| public override List<float> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListDoubleSerializer : Serializer<List<double>> |
| { |
| private static readonly ListSerializer<double> Fallback = new(); |
| |
| |
| |
| |
| public override List<double> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<double> value, bool hasGenerics) |
| { |
| List<double> list = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.Float64, false); |
| for (int i = 0; i < list.Count; i++) |
| { |
| context.Writer.WriteFloat64(list[i]); |
| } |
| } |
| |
| public override List<double> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class ListStringSerializer : Serializer<List<string>> |
| { |
| private static readonly ListSerializer<string> Fallback = new(); |
| |
| |
| |
| |
| public override List<string> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in List<string> value, bool hasGenerics) |
| { |
| List<string> list = value ?? []; |
| bool hasNull = false; |
| for (int i = 0; i < list.Count; i++) |
| { |
| if (list[i] is null) |
| { |
| hasNull = true; |
| break; |
| } |
| } |
| |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TypeId.String, hasNull); |
| if (hasNull) |
| { |
| for (int i = 0; i < list.Count; i++) |
| { |
| string? item = list[i]; |
| if (item is null) |
| { |
| context.Writer.WriteInt8((sbyte)RefFlag.Null); |
| continue; |
| } |
| |
| context.Writer.WriteInt8((sbyte)RefFlag.NotNullValue); |
| StringSerializer.WriteString(context, item); |
| } |
| |
| return; |
| } |
| |
| for (int i = 0; i < list.Count; i++) |
| { |
| StringSerializer.WriteString(context, list[i]); |
| } |
| } |
| |
| public override List<string> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetInt8Serializer : Serializer<HashSet<sbyte>> |
| { |
| private static readonly SetSerializer<sbyte> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<sbyte> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<sbyte> value, bool hasGenerics) |
| { |
| HashSet<sbyte> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.Int8, false); |
| foreach (sbyte item in set) |
| { |
| context.Writer.WriteInt8(item); |
| } |
| } |
| |
| public override HashSet<sbyte> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetInt16Serializer : Serializer<HashSet<short>> |
| { |
| private static readonly SetSerializer<short> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<short> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<short> value, bool hasGenerics) |
| { |
| HashSet<short> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.Int16, false); |
| foreach (short item in set) |
| { |
| context.Writer.WriteInt16(item); |
| } |
| } |
| |
| public override HashSet<short> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetIntSerializer : Serializer<HashSet<int>> |
| { |
| private static readonly SetSerializer<int> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<int> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<int> value, bool hasGenerics) |
| { |
| HashSet<int> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.VarInt32, false); |
| foreach (int item in set) |
| { |
| context.Writer.WriteVarInt32(item); |
| } |
| } |
| |
| public override HashSet<int> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetLongSerializer : Serializer<HashSet<long>> |
| { |
| private static readonly SetSerializer<long> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<long> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<long> value, bool hasGenerics) |
| { |
| HashSet<long> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.VarInt64, false); |
| foreach (long item in set) |
| { |
| context.Writer.WriteVarInt64(item); |
| } |
| } |
| |
| public override HashSet<long> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetUInt8Serializer : Serializer<HashSet<byte>> |
| { |
| private static readonly SetSerializer<byte> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<byte> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<byte> value, bool hasGenerics) |
| { |
| HashSet<byte> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.UInt8, false); |
| foreach (byte item in set) |
| { |
| context.Writer.WriteUInt8(item); |
| } |
| } |
| |
| public override HashSet<byte> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetUInt16Serializer : Serializer<HashSet<ushort>> |
| { |
| private static readonly SetSerializer<ushort> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<ushort> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<ushort> value, bool hasGenerics) |
| { |
| HashSet<ushort> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.UInt16, false); |
| foreach (ushort item in set) |
| { |
| context.Writer.WriteUInt16(item); |
| } |
| } |
| |
| public override HashSet<ushort> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetUIntSerializer : Serializer<HashSet<uint>> |
| { |
| private static readonly SetSerializer<uint> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<uint> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<uint> value, bool hasGenerics) |
| { |
| HashSet<uint> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.VarUInt32, false); |
| foreach (uint item in set) |
| { |
| context.Writer.WriteVarUInt32(item); |
| } |
| } |
| |
| public override HashSet<uint> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetULongSerializer : Serializer<HashSet<ulong>> |
| { |
| private static readonly SetSerializer<ulong> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<ulong> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<ulong> value, bool hasGenerics) |
| { |
| HashSet<ulong> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.VarUInt64, false); |
| foreach (ulong item in set) |
| { |
| context.Writer.WriteVarUInt64(item); |
| } |
| } |
| |
| public override HashSet<ulong> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetFloatSerializer : Serializer<HashSet<float>> |
| { |
| private static readonly SetSerializer<float> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<float> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<float> value, bool hasGenerics) |
| { |
| HashSet<float> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.Float32, false); |
| foreach (float item in set) |
| { |
| context.Writer.WriteFloat32(item); |
| } |
| } |
| |
| public override HashSet<float> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal sealed class SetDoubleSerializer : Serializer<HashSet<double>> |
| { |
| private static readonly SetSerializer<double> Fallback = new(); |
| |
| |
| |
| |
| public override HashSet<double> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in HashSet<double> value, bool hasGenerics) |
| { |
| HashSet<double> set = value ?? []; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TypeId.Float64, false); |
| foreach (double item in set) |
| { |
| context.Writer.WriteFloat64(item); |
| } |
| } |
| |
| public override HashSet<double> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal class PrimitiveLinkedListSerializer<T, TCodec> : Serializer<LinkedList<T>> |
| where TCodec : struct, IPrimitiveDictionaryCodec<T> |
| { |
| private static readonly LinkedListSerializer<T> Fallback = new(); |
| |
| |
| |
| |
| public override LinkedList<T> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in LinkedList<T> value, bool hasGenerics) |
| { |
| if (TCodec.IsNullable) |
| { |
| throw new InvalidDataException("nullable primitive codecs are not supported for linked-list fast path"); |
| } |
| |
| LinkedList<T> list = value ?? new LinkedList<T>(); |
| PrimitiveCollectionHeader.WriteListHeader(context, list.Count, hasGenerics, TCodec.WireTypeId, false); |
| foreach (T item in list) |
| { |
| TCodec.Write(context, item); |
| } |
| } |
| |
| public override LinkedList<T> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal class PrimitiveQueueSerializer<T, TCodec> : Serializer<Queue<T>> |
| where TCodec : struct, IPrimitiveDictionaryCodec<T> |
| { |
| private static readonly QueueSerializer<T> Fallback = new(); |
| |
| |
| |
| |
| public override Queue<T> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in Queue<T> value, bool hasGenerics) |
| { |
| if (TCodec.IsNullable) |
| { |
| throw new InvalidDataException("nullable primitive codecs are not supported for queue fast path"); |
| } |
| |
| Queue<T> queue = value ?? new Queue<T>(); |
| PrimitiveCollectionHeader.WriteListHeader(context, queue.Count, hasGenerics, TCodec.WireTypeId, false); |
| foreach (T item in queue) |
| { |
| TCodec.Write(context, item); |
| } |
| } |
| |
| public override Queue<T> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal class PrimitiveStackSerializer<T, TCodec> : Serializer<Stack<T>> |
| where TCodec : struct, IPrimitiveDictionaryCodec<T> |
| { |
| private static readonly StackSerializer<T> Fallback = new(); |
| |
| |
| |
| |
| public override Stack<T> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in Stack<T> value, bool hasGenerics) |
| { |
| if (TCodec.IsNullable) |
| { |
| throw new InvalidDataException("nullable primitive codecs are not supported for stack fast path"); |
| } |
| |
| Stack<T> stack = value ?? new Stack<T>(); |
| PrimitiveCollectionHeader.WriteListHeader(context, stack.Count, hasGenerics, TCodec.WireTypeId, false); |
| if (stack.Count == 0) |
| { |
| return; |
| } |
| |
| T[] topToBottom = stack.ToArray(); |
| for (int i = topToBottom.Length - 1; i >= 0; i--) |
| { |
| TCodec.Write(context, topToBottom[i]); |
| } |
| } |
| |
| public override Stack<T> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal class PrimitiveSortedSetSerializer<T, TCodec> : Serializer<SortedSet<T>> |
| where T : notnull |
| where TCodec : struct, IPrimitiveDictionaryCodec<T> |
| { |
| private static readonly SortedSetSerializer<T> Fallback = new(); |
| |
| |
| |
| |
| public override SortedSet<T> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in SortedSet<T> value, bool hasGenerics) |
| { |
| if (TCodec.IsNullable) |
| { |
| throw new InvalidDataException("nullable primitive codecs are not supported for sorted-set fast path"); |
| } |
| |
| SortedSet<T> set = value ?? new SortedSet<T>(); |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TCodec.WireTypeId, false); |
| foreach (T item in set) |
| { |
| TCodec.Write(context, item); |
| } |
| } |
| |
| public override SortedSet<T> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |
| |
| internal class PrimitiveImmutableHashSetSerializer<T, TCodec> : Serializer<ImmutableHashSet<T>> |
| where T : notnull |
| where TCodec : struct, IPrimitiveDictionaryCodec<T> |
| { |
| private static readonly ImmutableHashSetSerializer<T> Fallback = new(); |
| |
| |
| |
| |
| public override ImmutableHashSet<T> DefaultValue => null!; |
| |
| public override void WriteData(WriteContext context, in ImmutableHashSet<T> value, bool hasGenerics) |
| { |
| if (TCodec.IsNullable) |
| { |
| throw new InvalidDataException("nullable primitive codecs are not supported for immutable-hash-set fast path"); |
| } |
| |
| ImmutableHashSet<T> set = value ?? ImmutableHashSet<T>.Empty; |
| PrimitiveCollectionHeader.WriteListHeader(context, set.Count, hasGenerics, TCodec.WireTypeId, false); |
| foreach (T item in set) |
| { |
| TCodec.Write(context, item); |
| } |
| } |
| |
| public override ImmutableHashSet<T> ReadData(ReadContext context) |
| { |
| return Fallback.ReadData(context); |
| } |
| } |