Compare commits
No commits in common. "42d572d857078b2c09e0d3d6dd31397bc420806f" and "0d4015b07e60f9caa7775a1b43862551b81044f6" have entirely different histories.
42d572d857
...
0d4015b07e
5 changed files with 15 additions and 271 deletions
|
@ -1,5 +1,4 @@
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Data;
|
|
||||||
|
|
||||||
namespace Nyanbyte.Sysnya.Binary;
|
namespace Nyanbyte.Sysnya.Binary;
|
||||||
|
|
||||||
|
@ -16,10 +15,6 @@ public class BinaryEnumerator
|
||||||
private readonly ReadOnlyMemory<byte> _fullData;
|
private readonly ReadOnlyMemory<byte> _fullData;
|
||||||
private int _position = 0;
|
private int _position = 0;
|
||||||
|
|
||||||
public int Position => _position;
|
|
||||||
public int Remaining => _fullData.Length - _position;
|
|
||||||
public int Size => _fullData.Length;
|
|
||||||
|
|
||||||
public BinaryEnumerator Skip(int length)
|
public BinaryEnumerator Skip(int length)
|
||||||
{
|
{
|
||||||
_position += length;
|
_position += length;
|
||||||
|
@ -39,19 +34,6 @@ public class BinaryEnumerator
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint ReadUInt32()
|
|
||||||
{
|
|
||||||
uint value = _bigEndian ? BinaryPrimitives.ReadUInt32BigEndian(_fullData.Span[_position..(_position + 4)]) : BinaryPrimitives.ReadUInt32LittleEndian(_fullData.Span[_position..(_position + 4)]);
|
|
||||||
_position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadUInt32(out uint value)
|
|
||||||
{
|
|
||||||
value = ReadUInt32();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long ReadInt64()
|
public long ReadInt64()
|
||||||
{
|
{
|
||||||
long value = _bigEndian ? BinaryPrimitives.ReadInt64BigEndian(_fullData.Span[_position..(_position + 8)]) : BinaryPrimitives.ReadInt64LittleEndian(_fullData.Span[_position..(_position + 8)]);
|
long value = _bigEndian ? BinaryPrimitives.ReadInt64BigEndian(_fullData.Span[_position..(_position + 8)]) : BinaryPrimitives.ReadInt64LittleEndian(_fullData.Span[_position..(_position + 8)]);
|
||||||
|
@ -64,87 +46,4 @@ public class BinaryEnumerator
|
||||||
value = ReadInt64();
|
value = ReadInt64();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong ReadUInt64()
|
|
||||||
{
|
|
||||||
ulong value = _bigEndian ? BinaryPrimitives.ReadUInt64BigEndian(_fullData.Span[_position..(_position + 8)]) : BinaryPrimitives.ReadUInt64LittleEndian(_fullData.Span[_position..(_position + 8)]);
|
|
||||||
_position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadUInt64(out ulong value)
|
|
||||||
{
|
|
||||||
value = ReadUInt64();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public short ReadInt16()
|
|
||||||
{
|
|
||||||
short value = _bigEndian ? BinaryPrimitives.ReadInt16BigEndian(_fullData.Span[_position..(_position + 2)]) : BinaryPrimitives.ReadInt16LittleEndian(_fullData.Span[_position..(_position + 2)]);
|
|
||||||
_position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadInt16(out short value)
|
|
||||||
{
|
|
||||||
value = ReadInt16();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ushort ReadUInt16()
|
|
||||||
{
|
|
||||||
ushort value = _bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(_fullData.Span[_position..(_position + 2)]) : BinaryPrimitives.ReadUInt16LittleEndian(_fullData.Span[_position..(_position + 2)]);
|
|
||||||
_position += 2;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadUInt16(out ushort value)
|
|
||||||
{
|
|
||||||
value = ReadUInt16();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float ReadF32()
|
|
||||||
{
|
|
||||||
float value = _bigEndian ? BinaryPrimitives.ReadSingleBigEndian(_fullData.Span.Slice(_position)) : BinaryPrimitives.ReadSingleLittleEndian(_fullData.Span.Slice(_position));
|
|
||||||
_position += 4;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadF32(out float value)
|
|
||||||
{
|
|
||||||
value = ReadF32();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double ReadF64()
|
|
||||||
{
|
|
||||||
double value = _bigEndian ? BinaryPrimitives.ReadDoubleBigEndian(_fullData.Span.Slice(_position)) : BinaryPrimitives.ReadDoubleLittleEndian(_fullData.Span.Slice(_position));
|
|
||||||
_position += 8;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryEnumerator ReadF64(out double value)
|
|
||||||
{
|
|
||||||
value = ReadF64();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TNumeric ReadNumeric<TNumeric>() where TNumeric : struct, IConvertible
|
|
||||||
{
|
|
||||||
//TODO Refactor
|
|
||||||
object val = typeof(TNumeric).Name switch
|
|
||||||
{
|
|
||||||
"Int16" => ReadInt16(),
|
|
||||||
"UInt16" => ReadUInt16(),
|
|
||||||
"Int32" => ReadInt32(),
|
|
||||||
"UInt32" => ReadUInt32(),
|
|
||||||
"Int64" => ReadInt64(),
|
|
||||||
"UInt64" => ReadUInt64(),
|
|
||||||
|
|
||||||
_ => throw new DataException($"Invalid type: {typeof(TNumeric).FullName}")
|
|
||||||
};
|
|
||||||
|
|
||||||
return (TNumeric)val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,105 +3,23 @@ using System.Linq.Expressions;
|
||||||
|
|
||||||
namespace Nyanbyte.Sysnya.Binary;
|
namespace Nyanbyte.Sysnya.Binary;
|
||||||
|
|
||||||
public class BinaryStructMapperBuilder<T> where T : notnull, new()
|
public class BinaryStructMapperBuilder<T>
|
||||||
{
|
{
|
||||||
public BinaryStructMapperBuilder(int minMemoryLen = 0, bool bigEndian = true)
|
public BinaryStructMapperBuilder(T obj)
|
||||||
{
|
{
|
||||||
_minMemoryLen = minMemoryLen;
|
ArgumentNullException.ThrowIfNull(obj);
|
||||||
_bigEndian = bigEndian;
|
_obj = obj;
|
||||||
}
|
|
||||||
private readonly int _minMemoryLen;
|
|
||||||
private readonly bool _bigEndian;
|
|
||||||
private readonly LinkedList<Action<T, BinaryEnumerator>> _funcPipeline = new();
|
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindI16<M>(Expression<Func<T, M>> property)
|
|
||||||
{
|
|
||||||
Bind<M, short>(property);
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindU16<M>(Expression<Func<T, M>> property)
|
[NotNull]
|
||||||
{
|
private readonly T _obj;
|
||||||
Bind<M, ushort>(property);
|
private readonly Stack<Action<Memory<byte>>> _funcStack = new();
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindI32<M>(Expression<Func<T, M>> property)
|
public BinaryStructMapperBuilder<T> BindU32<M>(Expression<Func<M, T>> property)
|
||||||
{
|
{
|
||||||
Bind<M, int>(property);
|
var member = property.Body as MemberExpression;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindU32<M>(Expression<Func<T, M>> property)
|
|
||||||
{
|
|
||||||
Bind<M, uint>(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindI64<M>(Expression<Func<T, M>> property)
|
|
||||||
{
|
|
||||||
Bind<M, long>(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryStructMapperBuilder<T> BindU64<M>(Expression<Func<T, M>> property)
|
|
||||||
{
|
|
||||||
Bind<M, ulong>(property);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bind<M, TNumeric>(Expression<Func<T, M>> p) where TNumeric : struct, IConvertible
|
|
||||||
{
|
|
||||||
var member = p.Body as MemberExpression;
|
|
||||||
ArgumentNullException.ThrowIfNull(member);
|
ArgumentNullException.ThrowIfNull(member);
|
||||||
var prop = typeof(T).GetProperty(member.Member.Name)!;
|
_funcStack.Push(m => _obj.GetType().GetProperty(member.Member.Name)!.SetValue(_obj, m));
|
||||||
_funcPipeline.AddLast((obj, enu) =>
|
return this;
|
||||||
{
|
|
||||||
TNumeric value = enu.ReadNumeric<TNumeric>();
|
|
||||||
prop.SetValue(obj, value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryStructMapper<T> Build()
|
|
||||||
{
|
|
||||||
return new BinaryStructMapper<T>(_funcPipeline, _minMemoryLen, _bigEndian);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BinaryStructMapper<T> where T : notnull, new()
|
|
||||||
{
|
|
||||||
internal BinaryStructMapper(LinkedList<Action<T, BinaryEnumerator>> funcPipeline, int minMemoryLen, bool bigEndian)
|
|
||||||
{
|
|
||||||
_funcPipeline = funcPipeline;
|
|
||||||
_minMemoryLen = minMemoryLen;
|
|
||||||
_bigEndian = bigEndian;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly int _minMemoryLen;
|
|
||||||
private readonly bool _bigEndian;
|
|
||||||
private readonly LinkedList<Action<T, BinaryEnumerator>> _funcPipeline;
|
|
||||||
|
|
||||||
public T Map(byte[] bytes)
|
|
||||||
{
|
|
||||||
return Map(bytes.AsMemory());
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Map(Memory<byte> bytes)
|
|
||||||
{
|
|
||||||
BinaryEnumerator enu = new(bytes, _bigEndian);
|
|
||||||
if (bytes.Length < _minMemoryLen)
|
|
||||||
{
|
|
||||||
throw new ArgumentException($"Data shorter than minimum expected: expected {_minMemoryLen} bytes; got: {bytes.Length} bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
T obj = Activator.CreateInstance<T>();
|
|
||||||
var enumerator = _funcPipeline.GetEnumerator();
|
|
||||||
while (enumerator.MoveNext())
|
|
||||||
{
|
|
||||||
var func = enumerator.Current;
|
|
||||||
func.Invoke(obj, enu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Buffers.Binary;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Nyanbyte.Sysnya.Binary;
|
|
||||||
|
|
||||||
namespace Nyanbyte.Sysnya.CoreTests.Binary;
|
|
||||||
|
|
||||||
public class BinaryMapperTests
|
|
||||||
{
|
|
||||||
|
|
||||||
private class Dummy
|
|
||||||
{
|
|
||||||
public short Int16 { get; set; }
|
|
||||||
public ushort UInt16 { get; set; }
|
|
||||||
public int Int32 { get; set; }
|
|
||||||
public uint UInt32 { get; set; }
|
|
||||||
public long Int64 { get; set; }
|
|
||||||
public ulong UInt64 { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Map32Bit()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
Span<byte> bytes = stackalloc byte[8];
|
|
||||||
BinaryPrimitives.WriteUInt32BigEndian(bytes, 0xfeedbeef);
|
|
||||||
BinaryPrimitives.WriteInt32BigEndian(bytes[4..], 0xbeef);
|
|
||||||
|
|
||||||
BinaryStructMapperBuilder<Dummy> b = new(0, true);
|
|
||||||
|
|
||||||
// When
|
|
||||||
var mapper = b.BindU32(p => p.UInt32).BindI32(p => p.Int32).Build();
|
|
||||||
var dummy = mapper.Map(bytes.ToArray());
|
|
||||||
|
|
||||||
// Then
|
|
||||||
Assert.Equal(0xfeedbeef, dummy.UInt32);
|
|
||||||
Assert.Equal(0xbeef, dummy.Int32);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void MapAll()
|
|
||||||
{
|
|
||||||
// Given
|
|
||||||
Span<byte> bytes = stackalloc byte[28];
|
|
||||||
BinaryPrimitives.WriteUInt16BigEndian(bytes[0..], 0xbabe);
|
|
||||||
BinaryPrimitives.WriteInt16BigEndian(bytes[2..], 0xbf);
|
|
||||||
BinaryPrimitives.WriteUInt32BigEndian(bytes[4..], 0xfeedbeef);
|
|
||||||
BinaryPrimitives.WriteInt32BigEndian(bytes[8..], 0xbeef);
|
|
||||||
BinaryPrimitives.WriteUInt64BigEndian(bytes[12..], 0xbad1dea0babebebe);
|
|
||||||
BinaryPrimitives.WriteInt64BigEndian(bytes[20..], 0x1dea0babebebe);
|
|
||||||
|
|
||||||
BinaryStructMapperBuilder<Dummy> b = new(0, true);
|
|
||||||
|
|
||||||
// When
|
|
||||||
var mapper = b
|
|
||||||
.BindU16(p => p.UInt16).BindI16(p => p.Int16)
|
|
||||||
.BindU32(p => p.UInt32).BindI32(p => p.Int32)
|
|
||||||
.BindU64(p => p.UInt64).BindI64(p => p.Int64)
|
|
||||||
.Build();
|
|
||||||
var dummy = mapper.Map(bytes.ToArray());
|
|
||||||
|
|
||||||
// Then
|
|
||||||
Assert.Equal(0xbabe, dummy.UInt16);
|
|
||||||
Assert.Equal(0xbf, dummy.Int16);
|
|
||||||
Assert.Equal(0xfeedbeef, dummy.UInt32);
|
|
||||||
Assert.Equal(0xbeef, dummy.Int32);
|
|
||||||
Assert.Equal(0xbad1dea0babebebe, dummy.UInt64);
|
|
||||||
Assert.Equal(0x1dea0babebebe, dummy.Int64);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\Nyanbyte.Sysnya\Nyanbyte.Sysnya.csproj" />
|
<ProjectReference Include="..\..\src\Nyanbyte.Sysnya\Nyanbyte.Sysnya.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in a new issue