using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Runtime.Serialization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public Guid ID { get; set; }
public BitArray Input { get; set; }
public BitArray Output { get; set; }
protected BitArray Dirty { get; set; }
protected Chip(int inputs, int outputs)
Input = new BitArray(inputs, false);
Output = new BitArray(outputs, false);
Dirty = new BitArray(outputs, false);
public class BitArrayConverter : JsonConverter<BitArray>
public override BitArray ReadJson(JsonReader reader, Type objectType, BitArray existingValue, bool hasExistingValue, JsonSerializer serializer)
var bools = serializer.Deserialize<bool[]>(reader);
return bools == null ? null : new BitArray(bools);
public override void WriteJson(JsonWriter writer, BitArray value, JsonSerializer serializer)
serializer.Serialize(writer, value.Cast<bool>());
public class BitArrayConverter : JsonConverter<BitArray>
public override BitArray ReadJson(JsonReader reader, Type objectType, BitArray existingValue, bool hasExistingValue, JsonSerializer serializer)
if (reader.TokenType == JsonToken.Null)
else if (reader.TokenType != JsonToken.String)
throw new JsonSerializationException(string.Format("Unexpected token {0}", reader.TokenType));
var s = (string)reader.Value;
var bitArray = new BitArray(s.Length);
for (int i = 0; i < s.Length; i++)
bitArray[i] = s[i] == '0' ? false : s[i] == '1' ? true : throw new JsonSerializationException(string.Format("Unknown bit value {0}", s[i]));
public override void WriteJson(JsonWriter writer, BitArray value, JsonSerializer serializer)
writer.WriteValue(value.Cast<bool>().Aggregate(new StringBuilder(value.Length), (sb, b) => sb.Append(b ? "1" : "0")).ToString());
public class BitArrayConverter : JsonConverter<BitArray>
public byte[] Bytes { get; set; }
public int Length { get; set; }
public override BitArray ReadJson(JsonReader reader, Type objectType, BitArray existingValue, bool hasExistingValue, JsonSerializer serializer)
var dto = serializer.Deserialize<BitArrayDTO>(reader);
var bitArray = new BitArray(dto.Bytes);
bitArray.Length = dto.Length;
public override void WriteJson(JsonWriter writer, BitArray value, JsonSerializer serializer)
var dto = new BitArrayDTO
Bytes = value.BitArrayToByteArray(),
serializer.Serialize(writer, dto);
public static class BitArrayExtensions
public static byte[] BitArrayToByteArray(this BitArray bits)
byte[] ret = new byte[(bits.Length - 1) / 8 + 1];
public class ChipConverter : CustomCreationConverter<Chip>
public override bool CanConvert(Type objectType) { return objectType == typeof(Chip); }
public override Chip Create(Type objectType)
return (Chip)Activator.CreateInstance(typeof(Chip), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { 0, 0 }, null);
public static void Test()
var initial = new [] { true, true, false };
var initial2 = new [] { true, false, false, true, true, false };
Test<V1.BitArrayConverter>(initial, true);
Test<V2.BitArrayConverter>(initial, true);
Test<V3.BitArrayConverter>(initial, true);
Test<V1.BitArrayConverter>(initial2, false);
Test<V2.BitArrayConverter>(initial2, false);
Test<V3.BitArrayConverter>(initial2, false);
Test<V1.BitArrayConverter>(initial2.Concat(Enumerable.Range(0, byte.MaxValue+1).Select(i => unchecked((byte)i)).Reverse().SelectMany(b => AsBools(b))), false);
Test<V2.BitArrayConverter>(initial2.Concat(Enumerable.Range(0, byte.MaxValue+1).Select(i => unchecked((byte)i)).Reverse().SelectMany(b => AsBools(b))), false);
Test<V3.BitArrayConverter>(initial2.Concat(Enumerable.Range(0, byte.MaxValue+1).Select(i => unchecked((byte)i)).Reverse().SelectMany(b => AsBools(b))), false);
Test<V1.BitArrayConverter>(Enumerable.Empty<bool>(), false);
Test<V2.BitArrayConverter>(Enumerable.Empty<bool>(), false);
Test<V3.BitArrayConverter>(Enumerable.Empty<bool>(), false);
private static void Test<BitArrayConverter>(IEnumerable<bool> bools, bool print) where BitArrayConverter : JsonConverter, new()
Console.WriteLine("Testing {0} with {1} bools:", typeof(BitArrayConverter), bools.Count());
var settings = new JsonSerializerSettings
Converters = { new ChipConverter(), new BitArrayConverter() },
var s = Test(settings, bools);
Console.WriteLine(" Tests passed with Chip JSON: ");
Console.WriteLine(" Tests passed.");
static string Test(JsonSerializerSettings settings, IEnumerable<bool> bools)
var boolArray = bools.ToArray();
var array = new BitArray(boolArray);
var json = JsonConvert.SerializeObject(array, settings);
var array2 = JsonConvert.DeserializeObject<BitArray>(json, settings);
Assert.IsTrue(array.Cast<bool>().SequenceEqual(array2.Cast<bool>()));
var chip = (Chip)Activator.CreateInstance(typeof(Chip), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { array.Length, array.Length }, null);
var chipJson = JsonConvert.SerializeObject(chip, Formatting.Indented, settings);
var chip2 = JsonConvert.DeserializeObject<Chip>(chipJson, settings);
Assert.IsTrue(array.Cast<bool>().SequenceEqual(chip2.Input.Cast<bool>()));
Assert.IsTrue(array.Cast<bool>().SequenceEqual(chip2.Output.Cast<bool>()));
static IEnumerable<bool> AsBools(byte b)
yield return (b & (1 << 0)) != 0;
yield return (b & (1 << 1)) != 0;
yield return (b & (1 << 2)) != 0;
yield return (b & (1 << 3)) != 0;
yield return (b & (1 << 4)) != 0;
yield return (b & (1 << 5)) != 0;
yield return (b & (1 << 6)) != 0;
yield return (b & (1 << 7)) != 0;
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];