///|
/// Enforce the existing SDK's opaque bounded representation at execution adapters.
/// Descriptive source metadata cannot grant a value this semantic type.
fn sdk_integer_width(owner : String) -> String? {
match owner {
"morphir/SDK:int#int-16" => Some("int16")
"morphir/SDK:int#int-64" => Some("int64")
"morphir/SDK:int#byte" => Some("byte")
"morphir/SDK:int#uint-16" => Some("uint16")
"morphir/SDK:int#uint-32" => Some("uint32")
"morphir/SDK:int#uint-64" => Some("uint64")
_ => None
}
}
///|
fn validate_sdk_boundary(value : @protocol.Value) -> Unit raise {
match value {
Constructor("morphir/SDK:int#int-32", "morphir/SDK:int#int32", [Integer(n)]) => {
guard @sdk_int.to_int32(@integer.from_bigint(n)) is Some(_) else {
raise @protocol.Invalid("execution.int32_range")
}
}
Constructor("morphir/SDK:int#int-32", _, _) =>
raise @protocol.Invalid("execution.wrong_type")
Constructor(owner, tag, [Integer(n)]) if sdk_integer_width(owner)
is Some(width) => {
let expected_tag = "morphir/SDK:int#" +
(if width.has_prefix("int") {
width
} else {
owner.clamped_view(start="morphir/SDK:int#".length()).to_owned()
})
if tag != expected_tag {
raise @protocol.Invalid("execution.wrong_type")
}
let integer = @integer.from_bigint(n)
let fits = match width {
"int16" => @sdk_int.to_int16(integer) is Some(_)
"int64" => @sdk_int.to_int64(integer) is Some(_)
"byte" => @sdk_int.to_byte(integer) is Some(_)
"uint16" => @sdk_int.to_uint16(integer) is Some(_)
"uint32" => @sdk_int.to_uint32(integer) is Some(_)
"uint64" => @sdk_int.to_uint64(integer) is Some(_)
_ => false
}
if !fits {
raise @protocol.Invalid("execution." + width + "_range")
}
}
Constructor(owner, _, _) if sdk_integer_width(owner) is Some(_) =>
raise @protocol.Invalid("execution.wrong_type")
Constructor(_, _, items) | Product(items) | Sequence(items) =>
for item in items {
validate_sdk_boundary(item)
}
Record(fields) =>
for (_, item) in fields {
validate_sdk_boundary(item)
}
Optional(Some(item)) | Outcome(Ok(item)) | Outcome(Err(item)) =>
validate_sdk_boundary(item)
_ => ()
}
}