Skip to main content

Module 0x2::display

Defines a Display struct which defines the way an Object should be displayed. The intention is to keep data as independent from its display as possible, protecting the development process and keeping it separate from the ecosystem agreements.

Each of the fields of the Display object should allow for pattern substitution and filling-in the pieces using the data from the object T.

More entry functions might be added in the future depending on the use cases.

use 0x1::string;
use 0x2::event;
use 0x2::object;
use 0x2::package;
use 0x2::transfer;
use 0x2::tx_context;
use 0x2::vec_map;

Resource Display

The Display object. Defines the way a T instance should be displayed. Display object can only be created and modified with a PublisherCap, making sure that the rules are set by the owner of the type.

Each of the display properties should support patterns outside of the system, making it simpler to customize Display based on the property values of an Object.

// Example of a display object
Display<0x...::capy::Capy> {
fields:
<name, "Capy { genes }">
<link, "https://capy.art/capy/{ id }">
<image, "https://api.capy.art/capy/{ id }/svg">
<description, "Lovely Capy, one of many">
}

Uses only String type due to external-facing nature of the object, the property names have a priority over their types.

struct Display<T: key> has store, key
Fields
id: object::UID
fields: vec_map::VecMap<string::String, string::String>
Contains fields for display. Currently supported fields are: name, link, image and description.
version: u16
Version that can only be updated manually by the Publisher.

Struct DisplayCreated

Event: emitted when a new Display object has been created for type T. Type signature of the event corresponds to the type while id serves for the discovery.

Since Sui RPC supports querying events by type, finding a Display for the T would be as simple as looking for the first event with Display<T>.

struct DisplayCreated<T: key> has copy, drop
Fields

Struct VersionUpdated

Version of Display got updated -

struct VersionUpdated<T: key> has copy, drop
Fields

Constants

For when T does not belong to the package Publisher.

const ENotOwner: u64 = 0;

For when vectors passed into one of the multiple insert functions don't match in their lengths.

const EVecLengthMismatch: u64 = 1;

Function new

Create an empty Display object. It can either be shared empty or filled with data right away via cheaper set_owned method.

public fun new<T: key>(pub: &package::Publisher, ctx: &mut tx_context::TxContext): display::Display<T>
Implementation
public fun new<T: key>(pub: &Publisher, ctx: &mut TxContext): Display<T> {
    assert!(is_authorized<T>(pub), ENotOwner);
    create_internal(ctx)
}

Function new_with_fields

Create a new Display object with a set of fields.

public fun new_with_fields<T: key>(pub: &package::Publisher, fields: vector<string::String>, values: vector<string::String>, ctx: &mut tx_context::TxContext): display::Display<T>
Implementation
public fun new_with_fields<T: key>(
    pub: &Publisher, fields: vector<String>, values: vector<String>, ctx: &mut TxContext
): Display<T> {
    let len = fields.length();
    assert!(len == values.length(), EVecLengthMismatch);

    let mut i = 0;
    let mut display = new<T>(pub, ctx);
    while (i < len) {
        display.add_internal(fields[i], values[i]);
        i = i + 1;
    };

    display
}

Function create_and_keep

Create a new empty Display object and keep it.

public entry fun create_and_keep<T: key>(pub: &package::Publisher, ctx: &mut tx_context::TxContext)
Implementation
entry public fun create_and_keep<T: key>(pub: &Publisher, ctx: &mut TxContext) {
    transfer::public_transfer(new<T>(pub, ctx), ctx.sender())
}

Function update_version

Manually bump the version and emit an event with the updated version's contents.

public entry fun update_version<T: key>(display: &mut display::Display<T>)
Implementation
entry public fun update_version<T: key>(
    display: &mut Display<T>
) {
    display.version = display.version + 1;
    event::emit(VersionUpdated<T> {
        version: display.version,
        fields: *&display.fields,
        id: display.id.to_inner(),
    })
}

Function add

Sets a custom name field with the value.

public entry fun add<T: key>(self: &mut display::Display<T>, name: string::String, value: string::String)
Implementation
entry public fun add<T: key>(self: &mut Display<T>, name: String, value: String) {
    self.add_internal(name, value)
}

Function add_multiple

Sets multiple fields with values.

public entry fun add_multiple<T: key>(self: &mut display::Display<T>, fields: vector<string::String>, values: vector<string::String>)
Implementation
entry public fun add_multiple<T: key>(
    self: &mut Display<T>, fields: vector<String>, values: vector<String>
) {
    let len = fields.length();
    assert!(len == values.length(), EVecLengthMismatch);

    let mut i = 0;
    while (i < len) {
        self.add_internal(fields[i], values[i]);
        i = i + 1;
    };
}

Function edit

Change the value of the field. TODO (long run): version changes;

public entry fun edit<T: key>(self: &mut display::Display<T>, name: string::String, value: string::String)
Implementation
entry public fun edit<T: key>(self: &mut Display<T>, name: String, value: String) {
    let (_, _) = self.fields.remove(&name);
    self.add_internal(name, value)
}

Function remove

Remove the key from the Display.

public entry fun remove<T: key>(self: &mut display::Display<T>, name: string::String)
Implementation
entry public fun remove<T: key>(self: &mut Display<T>, name: String) {
    self.fields.remove(&name);
}

Function is_authorized

Authorization check; can be performed externally to implement protection rules for Display.

public fun is_authorized<T: key>(pub: &package::Publisher): bool
Implementation
public fun is_authorized<T: key>(pub: &Publisher): bool {
    pub.from_package<T>()
}

Function version

Read the version field.

public fun version<T: key>(d: &display::Display<T>): u16
Implementation
public fun version<T: key>(d: &Display<T>): u16 {
    d.version
}

Function fields

Read the fields field.

public fun fields<T: key>(d: &display::Display<T>): &vec_map::VecMap<string::String, string::String>
Implementation
public fun fields<T: key>(d: &Display<T>): &VecMap<String, String> {
    &d.fields
}

Function create_internal

Internal function to create a new Display<T>.

fun create_internal<T: key>(ctx: &mut tx_context::TxContext): display::Display<T>
Implementation
fun create_internal<T: key>(ctx: &mut TxContext): Display<T> {
    let uid = object::new(ctx);

    event::emit(DisplayCreated<T> {
        id: uid.to_inner()
    });

    Display {
        id: uid,
        fields: vec_map::empty(),
        version: 0,
    }
}

Function add_internal

Private method for inserting fields without security checks.

fun add_internal<T: key>(display: &mut display::Display<T>, name: string::String, value: string::String)
Implementation
fun add_internal<T: key>(display: &mut Display<T>, name: String, value: String) {
    display.fields.insert(name, value)
}