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