diff --git a/leopard.nim b/leopard.nim index 9a30d6e..60de3d7 100644 --- a/leopard.nim +++ b/leopard.nim @@ -1,279 +1,12 @@ -import pkg/stew/ptrops -import pkg/stew/results -import pkg/upraises +## Nim-Leopard +## Copyright (c) 2022 Status Research & Development GmbH +## Licensed under either of +## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +## * MIT license ([LICENSE-MIT](LICENSE-MIT)) +## at your option. +## This file may not be copied, modified, or distributed except according to +## those terms. -import ./leopard/wrapper +import ./leopard/leopard -export results - -push: {.upraises: [].} - -const - LeopardBadCodeMsg = "Bad RS code" - LeopardInconsistentSizeMsg = - "Buffer sizes must all be the same multiple of 64 bytes" - LeopardNeedLessDataMsg = "Too much recovery data received" - LeopardNotEnoughDataMsg = "Buffer counts are too low" - - MinBufferSize* = 64.uint - MinSymbols* = 1.uint - MaxTotalSymbols* = 65536.uint - -type - Data* = seq[seq[byte]] - - LeopardDefect* = object of Defect - - # It should not be necessary to redefine LeopardResult, but if that's not - # done here then defining LeopardError as `object of CatchableError` will - # cause a mystery crash at compile-time (symbol not found). Can workaround by - # defining as just `object`, but then when trying to work with LeopardResult - # errors in e.g. tests/test_leopard.nim the same mystery crash happens at - # compile-time. The problem may be related to use of importcpp in - # leopard/wrapper.nim, so it could be a compiler bug. By redefining - # LeopardResult in this module (and casting wrapper.LeopardResult values) the - # the problem is avoided. - LeopardResult* = enum - LeopardNotEnoughData = -11.cint # Buffer counts are too low - LeopardNeedLessData = -10.cint # Too much recovery data received - LeopardInconsistentSize = -9.cint # Buffer sizes must all be the same multiple of 64 bytes - LeopardBadCode = -8.cint # Bad RS code - LeopardCallInitialize = wrapper.LeopardCallInitialize - LeopardPlatform = wrapper.LeopardPlatform - LeopardInvalidInput = wrapper.LeopardInvalidInput - LeopardInvalidCounts = wrapper.LeopardInvalidCounts - LeopardInvalidSize = wrapper.LeopardInvalidSize - LeopardTooMuchData = wrapper.LeopardTooMuchData - LeopardNeedMoreData = wrapper.LeopardNeedMoreData - LeopardSuccess = wrapper.LeopardSuccess - - LeopardError* = object of CatchableError - code*: LeopardResult - - ParityData* = Data - - ReedSolomonCode* = tuple[codeword, data, parity: uint] # symbol counts - -# workaround for https://github.com/nim-lang/Nim/issues/19619 -# necessary for use of nim-leopard in nimbus-build-system projects because nbs -# ships libbacktrace by default -proc `$`*(err: LeopardError): string {.noSideEffect.} = - $err - -# https://github.com/catid/leopard/issues/12 -# https://www.cs.cmu.edu/~guyb/realworld/reedsolomon/reed_solomon_codes.html -# -# RS(255,239) -# --------------------------------- -# codeword symbols = 255 -# data symbols = 239 -# parity symbols = 255 - 239 = 16 - -proc RS*(codeword, data: Positive): ReedSolomonCode = - var - parity = codeword - data - - if parity < 0: parity = 0 - (codeword: codeword.uint, data: data.uint, parity: parity.uint) - -func isValid*(code: ReedSolomonCode): bool = - not ((code.codeword - code.data != code.parity) or - (code.parity > code.data) or (code.codeword < MinSymbols + 1) or - (code.data < MinSymbols) or (code.parity < MinSymbols) or - (code.codeword > MaxTotalSymbols)) - -proc leoInit*() = - if wrapper.leoInit() != 0: - raise (ref LeopardDefect)(msg: "Leopard-RS failed to initialize") - -proc encode*(code: ReedSolomonCode, data: Data): - Result[ParityData, LeopardError] = - if not code.isValid: - return err LeopardError(code: LeopardBadCode, msg: LeopardBadCodeMsg) - - var - data = data - - let - symbolBytes = data[0].len - - if data.len < code.data.int: - return err LeopardError(code: LeopardNotEnoughData, - msg: LeopardNotEnoughDataMsg) - - elif data.len > code.data.int: - return err LeopardError(code: LeopardTooMuchData, - msg: $leoResultString(wrapper.LeopardTooMuchData)) - - if symbolBytes < MinBufferSize.int or symbolBytes mod MinBufferSize.int != 0: - return err LeopardError(code: LeopardInvalidSize, - msg: $leoResultString(wrapper.LeopardInvalidSize)) - - var - enData = newSeq[pointer](code.data) - - for i in 0.. code.data.int: - return err LeopardError(code: LeopardTooMuchData, - msg: $leoResultString(wrapper.LeopardTooMuchData)) - - if parityData.len < code.parity.int: - return err LeopardError(code: LeopardNeedMoreData, - msg: $leoResultString(wrapper.LeopardNeedMoreData)) - - elif parityData.len > code.parity.int: - return err LeopardError(code: LeopardNeedLessData, - msg: LeopardNeedLessDataMsg) - - if symbolBytes < MinBufferSize or symbolBytes mod MinBufferSize != 0: - return err LeopardError(code: LeopardInvalidSize, - msg: $leoResultString(wrapper.LeopardInvalidSize)) - - var - deData = newSeq[pointer](code.data) - - for i in 0..