Skip to content

Commit

Permalink
Merge pull request #1113 from multiversx/explicit-enum-abi
Browse files Browse the repository at this point in the history
explicit enum ABI
  • Loading branch information
andrei-marinica authored Jun 16, 2023
2 parents 95ebfd5 + c1452c1 commit 7a7bc83
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 7 deletions.
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(),
}
}
}

0 comments on commit 7a7bc83

Please sign in to comment.