Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

explicit enum ABI #1113

Merged
merged 1 commit into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,23 @@
}
]
},
"OperationCompletionStatus": {
"type": "explicit-enum",
"variants": [
{
"docs": [
"indicates that operation was completed"
],
"name": "completed"
},
{
"docs": [
"indicates that operation was interrupted prematurely, due to low gas"
],
"name": "interrupted"
}
]
},
"ProposalFees": {
"type": "struct",
"fields": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,23 @@
}
]
},
"OperationCompletionStatus": {
"type": "explicit-enum",
"variants": [
{
"docs": [
"indicates that operation was completed"
],
"name": "completed"
},
{
"docs": [
"indicates that operation was interrupted prematurely, due to low gas"
],
"name": "interrupted"
}
]
},
"ProposalFees": {
"type": "struct",
"fields": [
Expand Down
2 changes: 1 addition & 1 deletion framework/base/src/abi/type_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub trait TypeAbi {
core::any::type_name::<Self>().into()
}

/// A type can provide more than its own description.
/// A type can provide more than its own name.
/// For instance, a struct can also provide the descriptions of the type of its fields.
/// TypeAbi doesn't care for the exact accumulator type,
/// which is abstracted by the TypeDescriptionContainer trait.
Expand Down
12 changes: 12 additions & 0 deletions framework/base/src/abi/type_description.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum TypeContents {
NotSpecified,
Enum(Vec<EnumVariantDescription>),
Struct(Vec<StructFieldDescription>),
ExplicitEnum(Vec<ExplicitEnumVariantDescription>),
}

impl TypeContents {
Expand All @@ -46,3 +47,14 @@ pub struct StructFieldDescription {
pub name: &'static str,
pub field_type: String,
}

/// An explicit enum is an enum that gets serialized by name instead of discriminant.
///
/// This makes it easier for humans to read readable in the transaction output.
///
/// It cannot have data fields, only simple enums allowed.
#[derive(Clone, Debug)]
pub struct ExplicitEnumVariantDescription {
pub docs: &'static [&'static str],
pub name: &'static str,
}
34 changes: 31 additions & 3 deletions framework/base/src/types/io/operation_completion_status.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use crate::{
abi::{TypeAbi, TypeName},
abi::{
ExplicitEnumVariantDescription, TypeAbi, TypeContents, TypeDescription,
TypeDescriptionContainer, TypeName,
},
api::ManagedTypeApi,
codec::{CodecFrom, EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput},
types::ManagedBuffer,
};

const COMPLETED_STR: &str = "completed";
const INTERRUPTED_STR: &str = "interrupted";

/// Standard way of signalling that an operation was interrupted early, before running out of gas.
/// An endpoint that performs a longer operation can check from time to time if it is running low
/// on gas and can decide to save its state and exit, so that it can continue the same operation later.
Expand All @@ -17,8 +23,8 @@ pub enum OperationCompletionStatus {
impl OperationCompletionStatus {
pub fn output_bytes(&self) -> &'static [u8] {
match self {
OperationCompletionStatus::Completed => b"completed",
OperationCompletionStatus::InterruptedBeforeOutOfGas => b"interrupted",
OperationCompletionStatus::Completed => COMPLETED_STR.as_bytes(),
OperationCompletionStatus::InterruptedBeforeOutOfGas => INTERRUPTED_STR.as_bytes(),
}
}

Expand Down Expand Up @@ -49,6 +55,28 @@ impl TypeAbi for OperationCompletionStatus {
fn type_name() -> TypeName {
TypeName::from("OperationCompletionStatus")
}

fn provide_type_descriptions<TDC: TypeDescriptionContainer>(accumulator: &mut TDC) {
let type_name = Self::type_name();

accumulator.insert(
type_name,
TypeDescription {
docs: &[],
name: Self::type_name(),
contents: TypeContents::ExplicitEnum([
ExplicitEnumVariantDescription {
docs: &["indicates that operation was completed"],
name: COMPLETED_STR,
},
ExplicitEnumVariantDescription {
docs: &["indicates that operation was interrupted prematurely, due to low gas"],
name: INTERRUPTED_STR,
}
].to_vec()),
},
);
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
26 changes: 23 additions & 3 deletions framework/meta/src/abi_json/type_abi_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ pub struct TypeDescriptionJson {
impl From<&TypeDescription> for TypeDescriptionJson {
fn from(abi: &TypeDescription) -> Self {
let content_type = match &abi.contents {
TypeContents::NotSpecified => "not_specified",
TypeContents::NotSpecified => "not-specified",
TypeContents::Enum(_) => "enum",
TypeContents::Struct(_) => "struct",
TypeContents::ExplicitEnum(_) => "explicit-enum",
};
let mut type_desc_json = TypeDescriptionJson {
content_type: content_type.to_string(),
Expand All @@ -44,6 +45,13 @@ impl From<&TypeDescription> for TypeDescriptionJson {
.push(EnumVariantDescriptionJson::from(variant));
}
},
TypeContents::ExplicitEnum(variants) => {
for variant in variants {
type_desc_json
.variants
.push(EnumVariantDescriptionJson::from(variant));
}
},
_ => {},
}

Expand Down Expand Up @@ -75,7 +83,8 @@ pub struct EnumVariantDescriptionJson {
#[serde(skip_serializing_if = "Vec::is_empty")]
pub docs: Vec<String>,
pub name: String,
pub discriminant: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub discriminant: Option<usize>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub fields: Vec<StructFieldDescriptionJson>,
}
Expand All @@ -85,7 +94,7 @@ impl From<&EnumVariantDescription> for EnumVariantDescriptionJson {
EnumVariantDescriptionJson {
docs: abi.docs.iter().map(|d| d.to_string()).collect(),
name: abi.name.to_string(),
discriminant: abi.discriminant,
discriminant: Some(abi.discriminant),
fields: abi
.fields
.iter()
Expand All @@ -94,3 +103,14 @@ impl From<&EnumVariantDescription> for EnumVariantDescriptionJson {
}
}
}

impl From<&ExplicitEnumVariantDescription> for EnumVariantDescriptionJson {
fn from(abi: &ExplicitEnumVariantDescription) -> Self {
EnumVariantDescriptionJson {
docs: abi.docs.iter().map(|d| d.to_string()).collect(),
name: abi.name.to_string(),
discriminant: None,
fields: Vec::new(),
}
}
}