Skip to content

Commit

Permalink
NetStandard2
Browse files Browse the repository at this point in the history
  • Loading branch information
Gekctek committed May 20, 2022
1 parent 27b4b13 commit aacd2c8
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 13 deletions.
16 changes: 10 additions & 6 deletions src/Candid/BinarySequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class BinarySequence
// Least signifcant bit (index 0) => Most signifcant bit (index n - 1)
private readonly bool[] bits;

public bool MostSignificantBit => this.bits[this.bits.Length - 1];

/// <param name="bits">Least signifcant to most ordered bits</param>
public BinarySequence(bool[] bits)
{
Expand All @@ -20,11 +22,11 @@ public BinarySequence(bool[] bits)
public BinarySequence ToTwosCompliment()
{
// If value most significant bit is `1`, the 2's compliment needs to be 1 bit larger to hold sign bit
if (this.bits.Last())
if (this.MostSignificantBit)
{
bool[] newBits = new bool[this.bits.Length + 1];
this.bits.CopyTo(newBits, 0);
return new BinarySequence(newBits).ToTwosCompliment();
return new BinarySequence(newBits);
}
bool[] bits = this.ToTwosComplimentInternal().ToArray();
return new BinarySequence(bits);
Expand All @@ -43,7 +45,6 @@ public BinarySequence ToReverseTwosCompliment()
public byte[] ToByteArray(bool bigEndian = false)
{
IEnumerable<byte> bytes = this.bits
.Reverse() // Reverse to start with least significant bit
.Chunk(8)
.Select(BitsToByte);
// Reverse if need big endian
Expand All @@ -65,7 +66,10 @@ byte BitsToByte(bool[] bits)
for (int i = 0; i < bits.Length; i++)
{
bool b = bits[i];
value |= 1 << i;
if (b)
{
value |= 1 << i;
}
}
return (byte)value;
}
Expand All @@ -74,7 +78,7 @@ byte BitsToByte(bool[] bits)
public override string ToString()
{
var stringBuilder = new StringBuilder();
foreach (bool bit in this.bits)
foreach (bool bit in this.bits.Reverse()) // Reverse to show LSB on right (normal display)
{
stringBuilder.Append(bit ? "1" : "0");
}
Expand All @@ -88,7 +92,7 @@ public static BinarySequence FromBytes(byte[] bytes, bool isBigEndian)
{
byteSeq = byteSeq.Reverse();
}
bool[] bits = bytes
bool[] bits = byteSeq
.SelectMany(ByteToBits)
.ToArray();
return new BinarySequence(bits);
Expand Down
2 changes: 1 addition & 1 deletion src/Candid/CandidTextParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private static CandidType GetNamedType(CandidTextTokenHelper helper)
// Check to see if text is recursive id like `μrec_1.record` vs just the type name `record`
if (type.StartsWith("μ"))
{
recursiveId = CandidId.Parse(type[1..]);
recursiveId = CandidId.Parse(type.Substring(1));
helper.MoveNextOrThrow();
helper.CurrentToken.ValidateType(CandidTextTokenType.Period); // Period seperates recursive id and type
helper.MoveNextOrThrow();
Expand Down
2 changes: 1 addition & 1 deletion src/Candid/EdjCase.ICP.Candid.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Theraot.Core" Version="3.2.11" />
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/Candid/Models/Principal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static Principal SelfAuthenticating(byte[] publicKey)
// bytes = digest + selfAuthenticatingSuffix
byte[] bytes = new byte[digest.Length + 1];
digest.CopyTo(bytes.AsSpan());
bytes[^1] = selfAuthenticatingSuffix;
bytes[bytes.Length - 1] = selfAuthenticatingSuffix;
return new Principal(bytes);
}

Expand Down
22 changes: 22 additions & 0 deletions src/Candid/NetStandardWorkarounds/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;

#if NETSTANDARD2_0
public static class DictionaryExtensions
{
public static TValue? GetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
{
if (dictionary == null) { throw new ArgumentNullException(nameof(dictionary)); } // using C# 6
if (key == null) { throw new ArgumentNullException(nameof(key)); } // using C# 6

TValue value;
return dictionary.TryGetValue(key, out value) ? value : defaultValue;
}
public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> source, out TKey Key, out TValue Value)
{
Key = source.Key;
Value = source.Value;
}
}
#endif
22 changes: 22 additions & 0 deletions src/Candid/NetStandardWorkarounds/IsExtenalInit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#if NETSTANDARD2_0

using System.ComponentModel;

// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices
{
/// <summary>
/// Reserved to be used by the compiler for tracking metadata.
/// This class should not be used by developers in source code.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit
{
}
}

#endif
2 changes: 1 addition & 1 deletion src/Candid/Utilities/ByteUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static BigInteger ToBigInteger(this byte[] bytes, bool isUnsigned, bool i
if (isUnsigned || isBigEndian)
{
BinarySequence bits = BinarySequence.FromBytes(bytes, isBigEndian);
if (isUnsigned)
if (isUnsigned && bits.MostSignificantBit)
{
// Convert unsigned to signed
bits = bits.ToTwosCompliment();
Expand Down
36 changes: 33 additions & 3 deletions test/Common.Tests/BinarySequenceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using Xunit;
Expand All @@ -11,12 +12,41 @@ namespace ICP.Candid.Tests
public class BinarySequenceTests
{
[Theory]
[InlineData("0A0B0C0D", "1010")]
public void BigEndian(string hexBytes, string binary)
[InlineData("0A0B0C0D", true, "00001010000010110000110000001101")]
[InlineData("0A0B0C0D", false, "00001101000011000000101100001010")]
public void BigEndian(string hexBytes, bool isBigEndian, string binary)
{
byte[] bytes = ByteUtil.FromHexString(hexBytes);
var sequence = BinarySequence.FromBytes(bytes, isBigEndian: true);
var sequence = BinarySequence.FromBytes(bytes, isBigEndian: isBigEndian);
Assert.Equal(binary, sequence.ToString());
}

[Theory]
[InlineData("0A", true, true, 10)]
[InlineData("0A", false, true, 10)]
[InlineData("0A", true, false, 10)]
[InlineData("0A", false, false, 10)]

[InlineData("FF", true, true, 255)]
[InlineData("FF", false, true, -1)]
[InlineData("FF", true, false, 255)]
[InlineData("FF", false, false, -1)]

[InlineData("FFFF", true, true, 65535)]
[InlineData("FFFF", false, true, -1)]
[InlineData("FFFF", true, false, 65535)]
[InlineData("FFFF", false, false, -1)]

[InlineData("FF0A", true, true, 65290)]
[InlineData("FF0A", false, true, -246)]
[InlineData("FF0A", true, false, 2815)]
[InlineData("FF0A", false, false, 2815)]
public void ToBigInteger(string hexBytes, bool isUnsigned, bool isBigEndian, long expected)
{
byte[] bytes = ByteUtil.FromHexString(hexBytes);
BigInteger actual = bytes.ToBigInteger(isUnsigned: isUnsigned, isBigEndian: isBigEndian);

Assert.Equal(expected, actual);
}
}
}

0 comments on commit aacd2c8

Please sign in to comment.