Serde

Kind of a port of Rust's Serde crate.
git clone https://git.philomathiclife.com/repos/Serde
Log | Files | Refs | README

BinDe.cs (9331B)


      1 using Serde.De;
      2 using Std;
      3 using Std.Maybe;
      4 using Std.Num;
      5 using Std.Result;
      6 using Std.Wrappers;
      7 using System;
      8 #region Namespaces
      9 namespace Serde.Bin.De {
     10     #region Types
     11     public interface IBinDeserializable<TSelf>: IDeserializable<TSelf> where TSelf: notnull, IBinDeserializable<TSelf> {
     12 
     13         #region Type-level Constructors
     14         #endregion
     15 
     16         #region Instance Constructors
     17         #endregion
     18 
     19         #region Type-level Fields
     20         #endregion
     21 
     22         #region Instance Fields
     23         #endregion
     24 
     25         #region Type-level Properties
     26         #endregion
     27 
     28         #region Instance Properties
     29         #endregion
     30 
     31         #region Type-level Functions
     32         public static abstract Result<TSelf, Error> De(ref Deserializer des);
     33         #endregion
     34 
     35         #region Instance Functions
     36         #endregion
     37 
     38         #region Operators
     39         #endregion
     40 
     41         #region Types
     42         #endregion
     43     }
     44     // Ensure the API mimics Serde.De.IDeserializer as much as possible.
     45     // If a function returns an Error, make sure the position is not moved.
     46     public ref struct Deserializer {
     47 
     48         #region Type-level Constructors
     49         #endregion
     50 
     51         #region Instance Constructors
     52         public Deserializer() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
     53         public Deserializer(ReadOnlySpan<byte> data) => _data = data;
     54         #endregion
     55 
     56         #region Type-level Fields
     57         #endregion
     58 
     59         #region Instance Fields
     60         ReadOnlySpan<byte> _data;
     61         #endregion
     62 
     63         #region Type-level Properties
     64         #endregion
     65 
     66         #region Instance Properties
     67         public readonly bool IsEndOfData => _data.IsEmpty;
     68         #endregion
     69 
     70         #region Type-level Functions
     71         public static Deserializer New(ReadOnlySpan<byte> data) => new(data);
     72         #endregion
     73 
     74         #region Instance Functions
     75         public Result<T, Error> DeserializeUnsafe<T>() where T: unmanaged {
     76             
     77             unsafe {
     78                 var size = sizeof(T);
     79                 var res = Peek((uint)size);
     80 
     81                 if (res.Length != size) {
     82                     return new(Error.InvalidLength((ulong)res.Length, (@string)$"{size.ToString()} bytes."));
     83                 } else {
     84                     _data = _data[res.Length..];
     85                     fixed (byte* ptr = res) { return new(*(T*)ptr); }
     86                 }
     87             }
     88         }
     89         public Result<bool, Error> DeserializeBool() {
     90 
     91             var copy = this;
     92             var val = copy.DeserializeByte();
     93 
     94             if (val.IsOK) {
     95                 var v = val.Unwrap();
     96 
     97                 if (v == byte.MinValue) {
     98                     this = copy;
     99                     return new(false);
    100                 } else if (v == byte.MaxValue) {
    101                     this = copy;
    102                     return new(true);
    103                 } else {
    104                     return new(Error.InvalidValue(Unexpected.Byte(v), (@string)"0 or 255."));
    105                 }
    106             } else {
    107                 return new(val.UnwrapErr());
    108             }
    109         }
    110         public Result<byte, Error> DeserializeByte() => DeserializeUnsafe<byte>();
    111         public Result<char, Error> DeserializeChar() => DeserializeUnsafe<char>();
    112         public ReadOnlySpan<char> DeserializeChars(uint len) => DeserializeSliceUnsafe<char>(len);
    113         public Result<System.DateTime, Error> DeserializeDateTime() {
    114 
    115             var copy = this;
    116             var val = copy.DeserializeLong();
    117 
    118             if (val.IsOK) {
    119                 var v = val.Unwrap();
    120                 try {
    121                     var date =  System.DateTime.FromBinary(v);
    122                     this = copy;
    123                     return new(date);
    124                 } catch (ArgumentException) {
    125                     return new(Error.InvalidValue(Unexpected.Long(v), (@string)"A long whose binary layout is the same as the binary layout of a valid System.DateTime."));
    126                 }
    127             } else {
    128                 return new(val.UnwrapErr());
    129             }
    130         }
    131         public Result<System.DateTimeOffset, Error> DeserializeDateTimeOffset() {
    132 
    133             var copy = this;
    134             var date = copy.DeserializeDateTime();
    135 
    136             if (date.IsOK) {
    137                 var time = copy.DeserializeTimeSpan();
    138                 
    139                 if (time.IsOK) {
    140                     try {
    141                         var offset = new System.DateTimeOffset(date.Unwrap(), time.Unwrap());
    142                         this = copy;
    143                         return new(offset);
    144                     } catch (ArgumentException) {
    145                         return new(Error.InvalidValue(Unexpected.TimeSpan(time.Unwrap()), (@string)"A valid System.DateTime and System.TimeSpan combination corresponding to a valid System.DateTimeOffset."));
    146                     }
    147                 } else {
    148                     return new(time.UnwrapErr());
    149                 }
    150             } else {
    151                 return new(date.UnwrapErr());
    152             }
    153         }
    154         public Result<decimal, Error> DeserializeDecimal() {
    155 
    156             var copy = this;
    157             var val = copy.DeserializeSliceUnsafe<int>(4);
    158 
    159             if (val.Length == 4) {
    160                 try {
    161                     var dec = new decimal(val);
    162                     this = copy;
    163                     return new(dec);
    164                 } catch (ArgumentException) {
    165                     unsafe {
    166                         fixed (int* ptr = val) {
    167                             var bytes = new byte[16];
    168                             new ReadOnlySpan<byte>((byte*)ptr, 16).CopyTo(bytes.AsSpan());
    169                             return new(Error.InvalidValue(Unexpected.Bytes(bytes), (@string)"A sequence of 4 ints returned from decimal.GetBits."));
    170                         }
    171                     }
    172                 }
    173             } else {
    174                 return new(Error.InvalidLength((ulong)val.Length * 4ul, (@string)"16 bytes."));
    175             }
    176         }
    177         public Result<double, Error> DeserializeDouble() => DeserializeUnsafe<double>();
    178         public Result<float, Error> DeserializeFloat() => DeserializeUnsafe<float>();
    179         public Result<System.Guid, Error> DeserializeGuid() => DeserializeUnsafe<System.Guid>();
    180         public Result<I128, Error> DeserializeI128() => DeserializeUnsafe<I128>();
    181         public Result<int, Error> DeserializeInt() => DeserializeUnsafe<int>();
    182         public Result<long, Error> DeserializeLong() => DeserializeUnsafe<long>();
    183         public Result<Maybe<TSome>, Error> DeserializeMaybe<TSome>() where TSome: notnull, IBinDeserializable<TSome> {
    184 
    185             var copy = this;
    186             var val = copy.DeserializeByte();
    187 
    188             if (val.IsOK) {
    189                 var v = val.Unwrap();
    190 
    191                 if (v == byte.MinValue) {
    192                     this = copy;
    193                     return new(Maybe<TSome>.None());
    194                 } else if (v == byte.MaxValue) {
    195                     var res = TSome.De(ref copy);
    196 
    197                     if (res.IsOK) {
    198                         this = copy;
    199                         return new(new Maybe<TSome>(res.Unwrap()));
    200                     } else {
    201                         return new(res.UnwrapErr());
    202                     }
    203                 } else {
    204                     return new(Error.InvalidValue(Unexpected.Byte(v), (@string)"0 or 255."));
    205                 }
    206             } else {
    207                 return new(val.UnwrapErr());
    208             }
    209 
    210         }
    211         public Result<sbyte, Error> DeserializeSbyte() => DeserializeUnsafe<sbyte>();
    212         public Result<short, Error> DeserializeShort() => DeserializeUnsafe<short>();
    213         // We deserialize the largest quantity of Ts possible less than or equal to len.
    214         // Partial Ts are not deserialized.
    215         public ReadOnlySpan<T> DeserializeSliceUnsafe<T>(uint len) where T: unmanaged {
    216 
    217             unsafe {
    218                 var size = sizeof(T);
    219                 var bytes = Read((uint)Math.Min(len * (uint)size, _data.Length - (_data.Length % size)));
    220                 fixed (byte* ptr = bytes) { return new ReadOnlySpan<T>(ptr, bytes.Length / size); }
    221             }
    222         }
    223         public Result<System.TimeSpan, Error> DeserializeTimeSpan() => DeserializeUnsafe<System.TimeSpan>();
    224         public Result<U128, Error> DeserializeU128() => DeserializeUnsafe<U128>();
    225         public Result<uint, Error> DeserializeUint() => DeserializeUnsafe<uint>();
    226         public Result<ulong, Error> DeserializeUlong() => DeserializeUnsafe<ulong>();
    227         public Result<Unit, Error> DeserializeUnit() => new(new Unit());
    228         public Result<ushort, Error> DeserializeUshort() => DeserializeUnsafe<ushort>();
    229         public override readonly bool Equals(object? _) => false;
    230         public override readonly int GetHashCode() => 0;
    231         public ReadOnlySpan<byte> Peek(uint len) => _data[..(int)Math.Min(len, _data.Length)];
    232         public ReadOnlySpan<byte> Read(uint len) {
    233 
    234             var l = (int)Math.Min(len, _data.Length);
    235             var bytes = _data[..l];
    236             _data = _data[l..];
    237             return bytes;
    238         }
    239         public override readonly string ToString() => string.Empty;
    240         #endregion
    241 
    242         #region Operators
    243         #endregion
    244 
    245         #region Types
    246         #endregion
    247     }
    248     #endregion
    249 
    250     #region Namespaces
    251     #endregion
    252 }
    253 #endregion