Я пишу рекурсивный кодировщик в crystal-lang для стандарта Ethereum RLP .
Что мне нужно сделать, это взять любые входящие данные BLOB-объект, который нужно закодировать и определить его тип. Пока я могу игнорировать недопустимые типы для простоты.
Допустимые типы для кодирования RLP будут двоичными Bytes
, строками String
или списками строк Array(String)
. Пока все хорошо, я написал три метода, которые учитывают три типа данных:
module Rlp
# rlp-encodes binary data
def self.encode(b : Bytes)
return "binary #{typeof(b)} #{b}"
end
# rlp-encodes lists data
def self.encode(l : Array(String))
return "listsy #{typeof(l)} #{l}"
end
# rlp-encodes string data
def self.encode(s : String)
return "strngy #{typeof(s)} #{s}"
end
end
Теперь, однако, здесь есть некоторая глубина, потому что массивы могут быть вложенными. Следовательно, этот кодер является рекурсивным. С учетом Array(String)
он дает ему некоторый префикс и кодирует String
с помощью Rlp.encode(s : String)
. Теперь логика c для наличия вложенного массива будет вызывать .encode
так часто, как это требуется для кодирования всего. Однако я не могу понять, как определить тип во время компиляции.
Например:
79 | Rlp.encode([["a", "b", "c"], ["cow", "dog", "cat"]])
^-----
Error: no overload matches 'Rlp.encode' with type Array(Array(String))
Верно, потому что у меня не реализован self.encode(l : Array(Array(String)))
и я не могу знать глубину вложения здесь, чтобы потенциально реализовать все возможные случаи.
Я пытался реализовать менее строгий метод оболочки self.encode(data)
, который не определяет тип данных, однако я в принципе ничего не могу сделать с data
потому что компилятор подразумевает типы данных, основанные на моем использовании, то есть:
# rlp-encodes _any_ data
def self.encode(data)
if typeof(data) == Int32
return Bytes.new data
elsif typeof(data) == Char
return String.new data
end
end
Передача 32
типа Int32
приведет к:
45 | return String.new data
Error: no overload matches 'String.new' with type Int32
Даже если этот код не будет нельзя вызывать с данными типа Int32
. Я не уверен, как действовать здесь. В любом случае, нужно ли быть более умным в отношении типов, используемых во время компиляции c во время компиляции?
В идеале я бы просто принял любые данные в качестве входных данных и сам обрабатывал различные случаи.