diff --git a/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs b/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs
index a908e96..73298e6 100644
--- a/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs
+++ b/Substrate.NetApi.Test/TypeConverters/BaseTypesTest.cs
@@ -5,9 +5,63 @@
using NUnit.Framework;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
+using System.Collections;
namespace Substrate.NetApi.Test
{
+ public sealed class Lsb0 : BaseType
+ {
+
+ ///
+ public override string TypeName()
+ {
+ return "Lsb0";
+ }
+
+ ///
+ public override byte[] Encode()
+ {
+ var result = new List();
+ return result.ToArray();
+ }
+
+ ///
+ public override void Decode(byte[] byteArray, ref int p)
+ {
+ var start = p;
+ var bytesLength = p - start;
+ TypeSize = bytesLength;
+ Bytes = new byte[bytesLength];
+ global::System.Array.Copy(byteArray, start, Bytes, 0, bytesLength);
+ }
+ }
+
+ public sealed class Msb0 : BaseType
+ {
+
+ ///
+ public override string TypeName()
+ {
+ return "Msb0";
+ }
+
+ ///
+ public override byte[] Encode()
+ {
+ var result = new List();
+ return result.ToArray();
+ }
+
+ ///
+ public override void Decode(byte[] byteArray, ref int p)
+ {
+ var start = p;
+ var bytesLength = p - start;
+ TypeSize = bytesLength;
+ Bytes = new byte[bytesLength];
+ global::System.Array.Copy(byteArray, start, Bytes, 0, bytesLength);
+ }
+ }
public class BaseTypesTest
{
[Test]
@@ -187,28 +241,53 @@ public void BaseOptTest()
Assert.IsTrue(exceptionThrown, "Exception not thrown for explicit cast with OptionFlag = false");
}
+ [Test]
+ public void BaseBitSeq_DisplayTest()
+ {
+ var testCase1 = "0xa00b80050000";
+ var baseBitSeqLsb0_1 = new BaseBitSeq();
+ var baseBitSeqMsb0_1 = new BaseBitSeq();
+ baseBitSeqLsb0_1.Create(testCase1);
+ baseBitSeqMsb0_1.Create(testCase1);
+
+ Assert.That(baseBitSeqLsb0_1.Encode(), Is.EquivalentTo(baseBitSeqMsb0_1.Encode()));
+ Assert.That(baseBitSeqLsb0_1.DisplayToBits(), Is.EqualTo("0b11010000_00000001_10100000_00000000_00000000"));
+ Assert.That(baseBitSeqMsb0_1.DisplayToBits(), Is.EqualTo("0b00001011_10000000_00000101_00000000_00000000"));
+
+ }
+
[Test]
public void BaseBitSeqTest()
{
var testCase1 = "0xa00b80050000";
- var bitSeqTest1 = FromBitString("0b11010000_00000001_10100000_00000000_00000000");
- var baseBitSeq1 = new BaseBitSeq();
- baseBitSeq1.Create(testCase1);
+ var bits = "0b11010000_00000001_10100000_00000000_00000000";
+ var bitSeqTest1 = FromBitString(bits);
+ var baseBitSeqLsb0_1 = new BaseBitSeq();
+ var baseBitSeqMsb0_1 = new BaseBitSeq();
+ baseBitSeqLsb0_1.Create(testCase1);
+ baseBitSeqMsb0_1.Create(testCase1);
for (int i = 0; i < bitSeqTest1.Length; i++)
{
- Assert.AreEqual(bitSeqTest1[i], baseBitSeq1.Value[i].Value);
+ Assert.AreEqual(bitSeqTest1[i], baseBitSeqLsb0_1.Value[i].Value);
}
- Assert.AreEqual(testCase1, Utils.Bytes2HexString(baseBitSeq1.Encode()).ToLower());
+ Assert.AreEqual(testCase1, Utils.Bytes2HexString(baseBitSeqLsb0_1.Encode()).ToLower());
+
+ var baseBitSeq1_bits = new BaseBitSeq();
+ baseBitSeq1_bits.CreateFromBitString(bits);
+ Assert.That(testCase1, Is.EqualTo(Utils.Bytes2HexString(baseBitSeq1_bits.Encode()).ToLower()));
+
+ var baseBitSeqMsb0_bits = new BaseBitSeq();
+ baseBitSeqMsb0_bits.CreateFromBitString(bits);
+ Assert.That(bits, Is.EqualTo(baseBitSeqMsb0_bits.DisplayToBits()));
// Let's create the same object but with the other Create() method
- var baseBitSeq1_1 = new BaseBitSeq();
- baseBitSeq1_1.Create(baseBitSeq1.Value);
- Assert.AreEqual(baseBitSeq1.Bytes, baseBitSeq1_1.Bytes);
- Assert.AreEqual(baseBitSeq1.Value, baseBitSeq1_1.Value);
- Assert.AreEqual(baseBitSeq1.TypeSize, baseBitSeq1_1.TypeSize);
+ var baseBitSeq1_1 = new BaseBitSeq();
+ baseBitSeq1_1.Create(baseBitSeqLsb0_1.Encode());
+ Assert.AreEqual(baseBitSeqLsb0_1.Bytes, baseBitSeq1_1.Bytes);
+ Assert.AreEqual(baseBitSeqLsb0_1.TypeSize, baseBitSeq1_1.TypeSize);
var bitSeqTest2 = FromBitString("0b10000010_10000010_00101000_00000000_00000000");
- var baseBitSeq2 = new BaseBitSeq();
+ var baseBitSeq2 = new BaseBitSeq();
baseBitSeq2.Create("0xa04141140000");
for (int i = 0; i < bitSeqTest1.Length; i++)
{
diff --git a/Substrate.NetApi/Model/Types/Base/BaseBitSeq.cs b/Substrate.NetApi/Model/Types/Base/BaseBitSeq.cs
index baad423..6ccfcb6 100644
--- a/Substrate.NetApi/Model/Types/Base/BaseBitSeq.cs
+++ b/Substrate.NetApi/Model/Types/Base/BaseBitSeq.cs
@@ -1,6 +1,9 @@
using Newtonsoft.Json;
+using Substrate.NetApi.Model.Types.Primitive;
using System;
+using System.Collections;
using System.Collections.Generic;
+using System.Linq;
namespace Substrate.NetApi.Model.Types.Base
{
@@ -31,19 +34,38 @@ public class BaseBitSeq : IType
[JsonIgnore]
public byte[] Bytes { get; internal set; }
+ private BitArray _bits { get; set; }
+
+ ///
+ /// Return if it is LSB (Least Significant Bit first) or MSB (Most Significant Bit first)
+ ///
+ public bool IsLsb {
+ get
+ {
+ switch (typeof(T2).Name.ToLower())
+ {
+ case "lsb0":
+ return true;
+ case "msb0":
+ return false;
+ default:
+ return true; // not sure if I should throw an exception here or just assume lsb0 (which is the default)
+ }
+ }
+ }
+
///
/// Encode to Bytes
///
///
public byte[] Encode()
{
- var result = new List
- {
- Reverse((byte)Value.Length)
- };
+ var result = new List();
+ result.AddRange(new CompactInteger(Value.Length * 8).Encode());
+
for (int i = 0; i < Value.Length; i++)
{
- result.AddRange(Reverse(Value[i].Encode()));
+ result.AddRange(IsLsb ? Reverse(Value[i].Encode()) : Value[i].Encode());
}
return result.ToArray();
}
@@ -56,16 +78,19 @@ public byte[] Encode()
public void Decode(byte[] byteArray, ref int p)
{
var start = p;
-
- var length = Reverse(byteArray[0]);
-
- p++;
+ int lengthInner = CompactInteger.Decode(byteArray, ref p);
+ var length = (int)Math.Ceiling((decimal)lengthInner / (decimal)8);
+ var tmpBytes = byteArray;
+ if (IsLsb)
+ {
+ tmpBytes = Reverse(byteArray);
+ }
var array = new T1[length];
for (var i = 0; i < length; i++)
{
var t = new T1();
- t.Decode(Reverse(byteArray), ref p);
+ t.Decode(tmpBytes, ref p);
array[i] = t;
}
@@ -74,6 +99,9 @@ public void Decode(byte[] byteArray, ref int p)
Bytes = new byte[TypeSize];
Array.Copy(byteArray, start, Bytes, 0, TypeSize);
Value = array;
+
+ // By default, BitArray is using Lsb0. So we need to reverse the bits again
+ _bits = new BitArray(array.SelectMany(x => Reverse(x.Encode())).ToArray());
}
///
@@ -104,6 +132,27 @@ public void Create(T1[] list)
///
public void CreateFromJson(string str) => Create(Utils.HexToByteArray(str));
+ ///
+ /// Create from string bits
+ /// Example : CreateFromBitString("0b11010000_00000001_10100000_00000000_00000000")
+ ///
+ ///
+ public void CreateFromBitString(string bits)
+ {
+ var s = bits.Replace("0b", "").Split('_');
+
+ var result = new List();
+
+ for (int i = 0; i < s.Length; i++)
+ {
+ byte b = Convert.ToByte(s[i], 2);
+ result.Add(IsLsb ? Reverse(b) : b);
+ }
+
+ result.InsertRange(0, new CompactInteger(result.Count * 8).Encode());
+ Create(result.ToArray());
+ }
+
///
/// Create from a byte array
///
@@ -121,7 +170,30 @@ public void Create(byte[] byteArray)
public IType New() => this;
///
- public override string ToString() => JsonConvert.SerializeObject(this);
+ public override string ToString() => $"{{ bits = {_bits.Count}, capacity = {_bits.Count}}} => [{DisplayToBits()}]";
+
+ ///
+ /// Display this instance to bits
+ ///
+ ///
+ public string DisplayToBits()
+ {
+ var bitString = new System.Text.StringBuilder(_bits.Count);
+ bitString.Append("0b");
+ for(int i = 0; i < _bits.Length; i++)
+ {
+ bitString.Append(_bits[i] ? '1' : '0');
+
+ if ((i + 1) % 8 == 0 && i != _bits.Count - 1)
+ {
+ bitString.Append("_");
+ }
+ }
+
+ return bitString.ToString();
+ }
+
+ public int InternalLength => _bits.Length;
///
/// Reverse