Crate gmeta

source ·
Expand description

Crate for providing metadata for Gear programs.

Metadata is used to describe the interface of a Gear program. For example, it can be used when uploading a contract using https://idea.gear-tech.io. The metadata informs the user about the contract’s interface and allows them to interact with it using custom types on web applications UI.

Another use case is to parse metadata in JavaScript using the gear-js library and get the metadata details for some custom UI.

Note that metadata is not required for a Gear program to work. It is only used to provide additional information about the contract. Also, metadata can be used for various purposes but we will focus on the use cases related to the https://idea.gear-tech.io.

To generate a metadata output file for a contract, you need:

  • Add gmeta crate to your Cargo.toml file.
  • Define an empty struct that will identify the contract metadata.
  • Implement the Metadata trait for this struct by defining the associated types of the trait.
  • Option 1: Call gear_wasm_builder::build_with_metadata function in build.rs file.
  • Option 2: Convert metadata to hex string using MetadataRepr::hex function and write it to the text file.

Examples

In this example we will create a simple ping-pong contract. Let’s define message types and metadata in a separate ping-io crate to be able to use it in both program and build.rs files.

We will define message types for handle() and state() functions.

  • ping-io crate:
#[no_std]
use gmeta::{InOut, Metadata, Out};
use gstd::prelude::*;

// Message type for `handle()` function.
#[derive(Encode, Decode, TypeInfo)]
pub enum PingPong {
    Ping,
    Pong,
}

// Metadata struct.
pub struct ContractMetadata;

impl Metadata for ContractMetadata {
    // The unit tuple is used as neither incoming nor outgoing messages are
    // expected in the `init()` function.
    type Init = ();
    // We use the same `PingPong` type for both incoming and outgoing
    // messages.
    type Handle = InOut<PingPong, PingPong>;
    // The unit tuple is used as we don't use asynchronous interaction in this
    // contract.
    type Others = ();
    // The unit tuple is used as we don't process any replies in this contract.
    type Reply = ();
    // The unit tuple is used as we don't process any signals in this contract.
    type Signal = ();
    // We return a counter value (`i32`) in the `state()` function in this contract.
    type State = Out<i32>;
}
  • ping program crate:
#[no_std]
use gmeta::{InOut, Metadata};
use gstd::{msg, prelude::*};
use ping_io::PingPong;

// Counter that will be incremented on each `Ping` message.
static mut COUNTER: i32 = 0;

#[no_mangle]
extern "C" fn handle() {
    // Load incoming message of `PingPong` type.
    let payload: PingPong = msg::load().expect("Unable to load");

    if let PingPong::Ping = payload {
        unsafe { COUNTER += 1 };
        // Send a reply message of `PingPong` type back to the sender.
        msg::reply(PingPong::Pong, 0).expect("Unable to reply");
    }
}

#[no_mangle]
extern "C" fn state() {
    msg::reply(unsafe { COUNTER }, 0).expect("Unable to reply");
}
  • build.rs file:
use ping_io::ContractMetadata;

fn main() {
    gear_wasm_builder::build_with_metadata::<ContractMetadata>();
}

You can also generate metadata manually and write it to the file without using build.rs:

use gmeta::{Metadata, Out};
use ping_io::ContractMetadata;
use std::fs;

let metadata_hex = ContractMetadata::repr().hex();
assert_eq!(metadata_hex.len(), 146);
fs::write("ping.meta.txt", metadata_hex).expect("Unable to write");

You can parse generated metadata file using gear-js API in JavaScript:

import { getProgramMetadata } from '@gear-js/api';
import { readFileSync } from 'fs';

const metadataHex = readFileSync('ping.meta.txt', 'utf-8');
const metadata = getProgramMetadata('0x' + metadataHex);

console.log('Registry:', metadata.regTypes);
console.log('Types:', metadata.types);

This will print the following:

Registry: Map(2) {
  0 => { name: 'RustOutPingPong', def: '{"_enum":["Ping","Pong"]}' },
  1 => { name: 'i32', def: null }
}
Types: {
  init: { input: null, output: null },
  handle: { input: 0, output: 0 },
  reply: { input: null, output: null },
  others: { input: null, output: null },
  signal: null,
  state: 1
}

Structs

  • A metatype abstraction.
  • Metadata internal representation.
  • Metawasm data.
  • A read-only registry containing types in their portable form for serialization.
  • The registry for space-efficient storage of type identifiers and definitions.
  • Types representation used by metadata.

Enums

Traits

  • Trait used for defining metadata.
  • Trait used to get information about types.
  • Trait used for registering types in registry.

Type Definitions

  • Type alias for incoming message type without any outgoing type.
  • Type alias for incoming/outgoing message types.
  • Type alias for outgoing message type without any incoming type.