///|
pub const CID_VERSION_0 : UInt64 = 0UL
///|
pub const CID_VERSION_1 : UInt64 = 1UL
///|
pub const DAG_PB_CODEC : UInt64 = 112UL
///|
/// CIDv0 or CIDv1 value.
pub(all) struct Cid {
version : UInt64
codec : UInt64
hash : Multihash
} derive(Eq, @debug.Debug)
///|
pub fn Cid::v1(
codec : UInt64,
hash : Multihash,
limits : Limits,
) -> Result[Cid, MoonLoomError] {
if codec == 0UL {
return Err(InvalidCodec(codec))
}
let encoded_hash = hash.encode()
let version = encode_u64(CID_VERSION_1)
let encoded_codec = encode_u64(codec)
let total_length = version.length() +
encoded_codec.length() +
encoded_hash.length()
match limits.check_input("CID", total_length) {
Ok(_) => Ok({ version: CID_VERSION_1, codec, hash, })
Err(err) => Err(err)
}
}
///|
pub fn Cid::v0(hash : Multihash, limits : Limits) -> Result[Cid, MoonLoomError] {
match hash.algorithm() {
Some(Sha2_256) => {
let bytes = hash.encode()
match limits.check_input("CID", bytes.length()) {
Ok(_) => Ok({ version: CID_VERSION_0, codec: DAG_PB_CODEC, hash, })
Err(err) => Err(err)
}
}
_ => Err(UnsupportedHashAlgorithm("CIDv0 requires sha2-256"))
}
}
///|
pub fn Cid::to_bytes(self : Cid) -> Bytes {
let writer = WireWriter::new()
if self.version == 0UL {
writer.write_bytes(self.hash.encode())
} else {
writer.write_varint(self.version)
writer.write_varint(self.codec)
writer.write_bytes(self.hash.encode())
}
writer.to_bytes()
}
///|
pub fn Cid::is_v0(self : Cid) -> Bool {
self.version == CID_VERSION_0
}
///|
pub fn Cid::codec_name(self : Cid) -> String? {
multicodec_name(self.codec)
}
///|
pub fn Cid::hash_algorithm(self : Cid) -> HashAlgorithm? {
self.hash.algorithm()
}
///|
fn decode_v1(input : BytesView, limits : Limits) -> Result[Cid, MoonLoomError] {
match decode_u64_with_limits(input, limits) {
Ok((codec, codec_length)) => {
if codec == 0UL {
return Err(InvalidCodec(codec))
}
if codec_length >= input.length() {
return Err(Truncated("CID codec", codec_length))
}
match Multihash::decode(input[codec_length:], limits) {
Ok((hash, hash_length)) => {
if codec_length + hash_length != input.length() {
return Err(InvalidCid("trailing bytes", codec_length + hash_length))
}
Ok({ version: CID_VERSION_1, codec, hash, })
}
Err(err) => Err(err)
}
}
Err(err) => Err(err)
}
}
///|
pub fn Cid::decode_bytes(
input : BytesView,
limits : Limits,
) -> Result[Cid, MoonLoomError] {
match limits.check_input("CID", input.length()) {
Ok(_) => ()
Err(err) => return Err(err)
}
if input.length() == 0 {
return Err(Truncated("CID", 0))
}
match decode_u64_with_limits(input, limits) {
Ok((first, first_length)) =>
if first == CID_VERSION_1 {
decode_v1(input[first_length:], limits)
} else {
match Multihash::decode(input, limits) {
Ok((hash, consumed)) => {
if consumed != input.length() {
return Err(InvalidCid("trailing bytes", consumed))
}
Cid::v0(hash, limits)
}
Err(err) => Err(err)
}
}
Err(err) => Err(err)
}
}
///|
pub fn Cid::to_text(self : Cid) -> Result[String, MoonLoomError] {
if self.version == 0UL {
Ok(encode_base58(self.to_bytes()))
} else {
multibase_encode(Base32, self.to_bytes())
}
}
///|
pub fn Cid::parse(
text : StringView,
limits : Limits,
) -> Result[Cid, MoonLoomError] {
match limits.check_input("CID", text.length()) {
Ok(_) => ()
Err(err) => return Err(err)
}
if text.length() == 0 {
return Err(Truncated("CID", 0))
}
let first = text.code_units()[0].to_int()
let first_char = first.unsafe_to_char()
match Base::from_prefix(first_char) {
Some(_) =>
match multibase_decode(text, limits) {
Ok(value) =>
match Cid::decode_bytes(value.data, limits) {
Ok(cid) =>
if cid.version == CID_VERSION_1 {
Ok(cid)
} else {
Err(InvalidCid("multibase is only valid for CIDv1", 0))
}
Err(err) => Err(err)
}
Err(err) => Err(err)
}
None => {
let _ = first
match decode_base58(text) {
Ok(bytes) =>
match Cid::decode_bytes(bytes, limits) {
Ok(cid) =>
if cid.version == 0UL {
Ok(cid)
} else {
Err(InvalidCid("CIDv1 requires a multibase prefix", 0))
}
Err(err) => Err(err)
}
Err(err) => Err(err)
}
}
}
}
///|
pub fn cid_from_content(
codec : UInt64,
algorithm : HashAlgorithm,
content : BytesView,
provider : HashProvider,
limits : Limits,
) -> Result[Cid, MoonLoomError] {
match provider.hash(algorithm, content) {
Ok(digest) =>
match Multihash::create(algorithm, digest, limits) {
Ok(hash) => Cid::v1(codec, hash, limits)
Err(err) => Err(err)
}
Err(err) => Err(err)
}
}
///|
pub fn cid_v0_from_content(
content : BytesView,
provider : HashProvider,
limits : Limits,
) -> Result[Cid, MoonLoomError] {
match provider.hash(Sha2_256, content) {
Ok(digest) =>
match Multihash::create(Sha2_256, digest, limits) {
Ok(hash) => Cid::v0(hash, limits)
Err(err) => Err(err)
}
Err(err) => Err(err)
}
}
///|
pub fn Cid::verify(
self : Cid,
content : BytesView,
provider : HashProvider,
limits : Limits,
) -> Result[Unit, MoonLoomError] {
self.hash.verify(content, provider, limits)
}
///|
pub extend Cid with Eq::{not_equal, equal}
///|
pub extend Cid with @debug.Debug::{to_repr}