/ binary_serialization / reader.nim
reader.nim
1 2 import 3 std/[tables, strutils, typetraits, macros, strformat], 4 stew/[endians2, objects], 5 faststreams/inputs, serialization/[formats, object_serialization, errors], 6 format 7 8 export 9 inputs 10 11 type 12 BinaryReader* = object 13 stream: InputStream 14 arrayLen: int 15 16 bitSize: int 17 workingByte: byte 18 remaining: int 19 20 Binary.setReader BinaryReader 21 22 proc init*(T: type BinaryReader, stream: InputStream): T = 23 T(stream: stream) 24 25 proc readValue*[T](r: var BinaryReader, value: var T) = 26 when sizeof(value) == 1: 27 type E = uint8 28 elif sizeof(value) == 2: 29 type E = uint16 30 elif sizeof(value) == 4: 31 type E = uint32 32 elif sizeof(value) == 8: 33 type E = uint64 34 35 when value is SomeUnsignedInt: 36 when value is uint8: 37 if r.bitSize > 0: 38 let mask = ((1 shl r.bitSize) - 1).uint8 39 r.remaining.dec(r.bitSize) 40 value = (r.workingByte shr r.remaining) and mask 41 return 42 let length = sizeof(value) 43 value = fromBytes(type value, r.stream.read(length), bigEndian) 44 elif value is enum: 45 var asUInt: E 46 r.readValue(asUInt) 47 #TODO raise instead 48 assert value.checkedEnumAssign(asUInt) 49 elif value is set: 50 var asUInt: E 51 r.readValue(asUInt) 52 #TODO is this safe enough? 53 value = cast[type(value)](asUInt) 54 elif value is object: 55 value.enumInstanceSerializedFields(fieldName, field): 56 when field.hasCustomPragma(bin_len): 57 let it = value 58 #TODO safer conversion 59 r.arrayLen = int(field.getCustomPragmaVal(bin_len)) 60 61 when field.hasCustomPragma(bin_bitsize): 62 when field isnot uint8: 63 {.error: "bit_bitsize only applies to byte".} 64 r.bitSize = (int)field.getCustomPragmaVal(bin_bitsize) 65 assert r.bitSize in 1 ..< 8 66 67 if r.remaining == 0: 68 r.workingByte = r.stream.read 69 r.remaining = 8 70 71 var vall: type(field) 72 r.readValue(vall) 73 field = vall 74 r.bitSize = 0 75 elif value is seq: 76 for _ in 0 ..< r.arrayLen: 77 var subValue: type(value[0]) 78 r.readValue(subValue) 79 value.add(subValue) 80 elif value is array: 81 for i in 0 ..< value.len: 82 r.readValue(value[i]) 83 else: 84 {.error: "Unsupported type " & $type(value).}