Candidの int は Nimの int / int64 ではなく、任意精度整数型に対応させるべきです。
Candid仕様上、int はビット幅に上限がない整数です。wire formatはSLEB128です。したがって int64 でも厳密な型対応にはなりません。(ICP Developer Docs) Nimの組み込み整数型は最大でも通常 int64 で、任意精度ではありません。(Nim Programming Language)
nicp_cdk なら、私はCDK専用の型を作るのを推奨します。
type
CandidInt* = object
negative*: bool
magnitude*: seq[byte] # little-endian limbs/bytes
あるいはもう少し実装しやすく、
type
CandidInt* = object
sign*: int8 # -1, 0, +1
limbs*: seq[uint32] # little-endian
です。
そしてマッピングを明確にします。
Candid | Nim
-- | --
int8 | int8
int16 | int16
int32 | int32
int64 | int64
int | CandidInt(任意精度)
nat8 | uint8
nat16 | uint16
nat32 | uint32
nat64 | uint64
nat | CandidNat(任意精度)
特に、int を int64 にするのは避けるべきです。今回のPlayground timestamp程度なら int64 に収まりますが、Candid型システムとしては不正確です。
nicp_cdkならさらにこうしたい
CandidInt と CandidNat を別々に巨大整数として実装するより、
type
CandidNat* = object
limbs*: seq[uint32]
CandidInt* = object
negative*: bool
magnitude*: CandidNat
にすると扱いやすいです。
SLEB128/ULEB128も、
proc encodeULEB128*(value: CandidNat): seq[byte]
proc decodeULEB128Big*(data: openArray[byte], offset: var int): CandidNat
proc encodeSLEB128*(value: CandidInt): seq[byte]
proc decodeSLEB128Big*(data: openArray[byte], offset: var int): CandidInt
に変更します。
現状の、
proc encodeSLEB128*(n: int32): seq[byte]
は int32 / int64 系Candid型の補助には使えても、Candid int のencoderとして使うべきではありません。
便利さのための変換
ユーザーに毎回BigIntを書かせる必要はありません。
proc candidInt*(x: int): CandidInt
proc candidInt*(x: int64): CandidInt
proc candidInt*(x: string): CandidInt
proc candidNat*(x: uint): CandidNat
proc candidNat*(x: uint64): CandidNat
proc candidNat*(x: string): CandidNat
として、
let a = candidInt(123)
let b = candidInt("170000000000000000000000000000000")
let c = candidInt("-999999999999999999999999999999")
とできるようにするのがよいです。
さらに CandidValue も、
of ctInt:
intVal*: CandidInt
of ctNat:
natVal*: CandidNat
に変えるのが型として正しいです。
結論としては Candid int = 独自の任意精度 CandidInt、Candid nat = 独自の任意精度 CandidNat が最も妥当です。 int64 を暫定対応にするより、このタイミングでCandidの型定義そのものを直した方が後で楽です。
Candidの
int は
Nimの int / int64 ではなく、任意精度整数型に対応させるべきです。
Candid仕様上、int はビット幅に上限がない整数です。wire formatはSLEB128です。したがって int64 でも厳密な型対応にはなりません。([ICP Developer Docs]1) Nimの組み込み整数型は最大でも通常 int64 で、任意精度ではありません。([Nim Programming Language]2)
nicp_cdk なら、私はCDK専用の型を作るのを推奨します。
type
CandidInt* = object
negative*: bool
magnitude*: seq[byte] # little-endian limbs/bytes
あるいはもう少し実装しやすく、
type
CandidInt* = object
sign*: int8 # -1, 0, +1
limbs*: seq[uint32] # little-endian
です。
そしてマッピングを明確にします。
| Candid |
Nim |
int8 |
int8 |
int16 |
int16 |
int32 |
int32 |
int64 |
int64 |
int |
CandidInt(任意精度) |
nat8 |
uint8 |
nat16 |
uint16 |
nat32 |
uint32 |
nat64 |
uint64 |
nat |
CandidNat(任意精度) |
特に、int を int64 にするのは避けるべきです。今回のPlayground timestamp程度なら int64 に収まりますが、Candid型システムとしては不正確です。
nicp_cdkならさらにこうしたい
CandidInt と CandidNat を別々に巨大整数として実装するより、
type
CandidNat* = object
limbs*: seq[uint32]
CandidInt* = object
negative*: bool
magnitude*: CandidNat
にすると扱いやすいです。
SLEB128/ULEB128も、
proc encodeULEB128*(value: CandidNat): seq[byte]
proc decodeULEB128Big*(data: openArray[byte], offset: var int): CandidNat
proc encodeSLEB128*(value: CandidInt): seq[byte]
proc decodeSLEB128Big*(data: openArray[byte], offset: var int): CandidInt
に変更します。
現状の、
proc encodeSLEB128*(n: int32): seq[byte]
は int32 / int64 系Candid型の補助には使えても、Candid int のencoderとして使うべきではありません。
便利さのための変換
ユーザーに毎回BigIntを書かせる必要はありません。
proc candidInt*(x: int): CandidInt
proc candidInt*(x: int64): CandidInt
proc candidInt*(x: string): CandidInt
proc candidNat*(x: uint): CandidNat
proc candidNat*(x: uint64): CandidNat
proc candidNat*(x: string): CandidNat
として、
let a = candidInt(123)
let b = candidInt("170000000000000000000000000000000")
let c = candidInt("-999999999999999999999999999999")
とできるようにするのがよいです。
さらに CandidValue も、
of ctInt:
intVal*: CandidInt
of ctNat:
natVal*: CandidNat
に変えるのが型として正しいです。
結論としては Candid int = 独自の任意精度 CandidInt、Candid nat = 独自の任意精度 CandidNat が最も妥当です。 int64 を暫定対応にするより、このタイミングでCandidの型定義そのものを直した方が後で楽です。
Candidの
intは Nimのint/int64ではなく、任意精度整数型に対応させるべきです。Candid仕様上、
intはビット幅に上限がない整数です。wire formatはSLEB128です。したがってint64でも厳密な型対応にはなりません。(ICP Developer Docs) Nimの組み込み整数型は最大でも通常int64で、任意精度ではありません。(Nim Programming Language)nicp_cdkなら、私はCDK専用の型を作るのを推奨します。あるいはもう少し実装しやすく、
です。
そしてマッピングを明確にします。
Candid | Nim -- | -- int8 | int8 int16 | int16 int32 | int32 int64 | int64 int | CandidInt(任意精度) nat8 | uint8 nat16 | uint16 nat32 | uint32 nat64 | uint64 nat | CandidNat(任意精度)特に、
intをint64にするのは避けるべきです。今回のPlayground timestamp程度ならint64に収まりますが、Candid型システムとしては不正確です。nicp_cdkならさらにこうしたい
CandidIntとCandidNatを別々に巨大整数として実装するより、にすると扱いやすいです。
SLEB128/ULEB128も、
に変更します。
現状の、
は
int32/int64系Candid型の補助には使えても、Candidintのencoderとして使うべきではありません。便利さのための変換
ユーザーに毎回BigIntを書かせる必要はありません。
として、
とできるようにするのがよいです。
さらに
CandidValueも、に変えるのが型として正しいです。
結論としては
CandidのCandid int = 独自の任意精度 CandidInt、Candid nat = 独自の任意精度 CandidNatが最も妥当です。int64を暫定対応にするより、このタイミングでCandidの型定義そのものを直した方が後で楽です。intは Nimのint/int64ではなく、任意精度整数型に対応させるべきです。Candid仕様上、
intはビット幅に上限がない整数です。wire formatはSLEB128です。したがってint64でも厳密な型対応にはなりません。([ICP Developer Docs]1) Nimの組み込み整数型は最大でも通常int64で、任意精度ではありません。([Nim Programming Language]2)nicp_cdkなら、私はCDK専用の型を作るのを推奨します。あるいはもう少し実装しやすく、
です。
そしてマッピングを明確にします。
int8int8int16int16int32int32int64int64intCandidInt(任意精度)nat8uint8nat16uint16nat32uint32nat64uint64natCandidNat(任意精度)特に、
intをint64にするのは避けるべきです。今回のPlayground timestamp程度ならint64に収まりますが、Candid型システムとしては不正確です。nicp_cdkならさらにこうしたい
CandidIntとCandidNatを別々に巨大整数として実装するより、にすると扱いやすいです。
SLEB128/ULEB128も、
に変更します。
現状の、
は
int32/int64系Candid型の補助には使えても、Candidintのencoderとして使うべきではありません。便利さのための変換
ユーザーに毎回BigIntを書かせる必要はありません。
として、
とできるようにするのがよいです。
さらに
CandidValueも、に変えるのが型として正しいです。
結論としては
Candid int = 独自の任意精度 CandidInt、Candid nat = 独自の任意精度 CandidNatが最も妥当です。int64を暫定対応にするより、このタイミングでCandidの型定義そのものを直した方が後で楽です。