Skip to main content

Module 0x2::dynamic_field

In addition to the fields declared in its type definition, an IOTA object can have dynamic fields that can be added after the object has been constructed. Unlike ordinary field names (which are always statically declared identifiers) a dynamic field name can be any value with the copy, drop, and store abilities, e.g. an integer, a boolean, or a string. This gives IOTA programmers the flexibility to extend objects on-the-fly, and it also serves as a building block for core collection types

use 0x1::option; use 0x2::object;

Resource Field

Internal object used for storing the field and value

struct Field<Name: copy, drop, store, Value: store> has key

Fields
id: object::UID

Determined by the hash of the object ID, the field name value and it's type, i.e. hash(parent.id || name || Name)

name: Name

The value for the name of this field

value: Value

The value bound to this field

Constants

Failed to serialize the field's name

const EBCSSerializationFailure: u64 = 3;

The object added as a dynamic field was previously a shared object

const ESharedObjectOperationNotSupported: u64 = 4;

The object already has a dynamic field with this name (with the value and type specified)

const EFieldAlreadyExists: u64 = 0;

Cannot load dynamic field. The object does not have a dynamic field with this name (with the value and type specified)

const EFieldDoesNotExist: u64 = 1;

The object has a field with that name, but the value type does not match

const EFieldTypeMismatch: u64 = 2;

Function add

Adds a dynamic field to the object object: &mut UID at field specified by name: Name. Aborts with EFieldAlreadyExists if the object already has that field with that name.

public fun add<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name, value: Value)

Implementation

public fun add<Name: copy + drop + store, Value: store>( // we use &mut UID in several spots for access control object: &mut UID, name: Name, value: Value, ) { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); assert!(!has_child_object(object_addr, hash), EFieldAlreadyExists); let field = Field { id: object::new_uid_from_hash(hash), name, value, }; add_child_object(object_addr, field) }

Function borrow

Immutably borrows the objects dynamic field with the name specified by name: Name. Aborts with EFieldDoesNotExist if the object does not have a field with that name. Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified type.

public fun borrow<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): &Value

Implementation

public fun borrow<Name: copy + drop + store, Value: store>( object: &UID, name: Name, ): &Value { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); let field = borrow_child_object<Field<Name, Value>>(object, hash); &field.value }

Function borrow_mut

Mutably borrows the objects dynamic field with the name specified by name: Name. Aborts with EFieldDoesNotExist if the object does not have a field with that name. Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified type.

public fun borrow_mut<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): &mut Value

Implementation

public fun borrow_mut<Name: copy + drop + store, Value: store>( object: &mut UID, name: Name, ): &mut Value { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); let field = borrow_child_object_mut<Field<Name, Value>>(object, hash); &mut field.value }

Function remove

Removes the objects dynamic field with the name specified by name: Name and returns the bound value. Aborts with EFieldDoesNotExist if the object does not have a field with that name. Aborts with EFieldTypeMismatch if the field exists, but the value does not have the specified type.

public fun remove<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): Value

Implementation

public fun remove<Name: copy + drop + store, Value: store>( object: &mut UID, name: Name, ): Value { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); let Field { id, name: _, value } = remove_child_object<Field<Name, Value>>(object_addr, hash); id.delete(); value }

Function exists_

Returns true if and only if the object has a dynamic field with the name specified by name: Name but without specifying the Value type

public fun exists_<Name: copy, drop, store>(object: &object::UID, name: Name): bool

Implementation

public fun exists_<Name: copy + drop + store>( object: &UID, name: Name, ): bool { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); has_child_object(object_addr, hash) }

Function remove_if_exists

Removes the dynamic field if it exists. Returns the some(Value) if it exists or none otherwise.

public fun remove_if_exists<Name: copy, drop, store, Value: store>(object: &mut object::UID, name: Name): option::Option<Value>

Implementation

public fun remove_if_exists<Name: copy + drop + store, Value: store>( object: &mut UID, name: Name ): Option<Value> { if (exists_<Name>(object, name)) { option::some(remove(object, name)) } else { option::none() } }

Function exists_with_type

Returns true if and only if the object has a dynamic field with the name specified by name: Name with an assigned value of type Value.

public fun exists_with_type<Name: copy, drop, store, Value: store>(object: &object::UID, name: Name): bool

Implementation

public fun exists_with_type<Name: copy + drop + store, Value: store>( object: &UID, name: Name, ): bool { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); has_child_object_with_ty<Field<Name, Value>>(object_addr, hash) }

Function field_info

public(friend) fun field_info<Name: copy, drop, store>(object: &object::UID, name: Name): (&object::UID, address)

Implementation

public(package) fun field_info<Name: copy + drop + store>( object: &UID, name: Name, ): (&UID, address) { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); let Field { id, name: _, value } = borrow_child_object<Field<Name, ID>>(object, hash); (id, value.to_address()) }

Function field_info_mut

public(friend) fun field_info_mut<Name: copy, drop, store>(object: &mut object::UID, name: Name): (&mut object::UID, address)

Implementation

public(package) fun field_info_mut<Name: copy + drop + store>( object: &mut UID, name: Name, ): (&mut UID, address) { let object_addr = object.to_address(); let hash = hash_type_and_key(object_addr, name); let Field { id, name: _, value } = borrow_child_object_mut<Field<Name, ID>>(object, hash); (id, value.to_address()) }

Function hash_type_and_key

May abort with EBCSSerializationFailure.

public(friend) fun hash_type_and_key<K: copy, drop, store>(parent: address, k: K): address

Implementation

public(package) native fun hash_type_and_key<K: copy + drop + store>(parent: address, k: K): address;

Function add_child_object

public(friend) fun add_child_object<Child: key>(parent: address, child: Child)

Implementation

public(package) native fun add_child_object<Child: key>(parent: address, child: Child);

Function borrow_child_object

throws EFieldDoesNotExist if a child does not exist with that ID or throws EFieldTypeMismatch if the type does not match, and may also abort with EBCSSerializationFailure we need two versions to return a reference or a mutable reference

public(friend) fun borrow_child_object<Child: key>(object: &object::UID, id: address): &Child

Implementation

public(package) native fun borrow_child_object<Child: key>(object: &UID, id: address): &Child;

Function borrow_child_object_mut

public(friend) fun borrow_child_object_mut<Child: key>(object: &mut object::UID, id: address): &mut Child

Implementation

public(package) native fun borrow_child_object_mut<Child: key>(object: &mut UID, id: address): &mut Child;

Function remove_child_object

throws EFieldDoesNotExist if a child does not exist with that ID or throws EFieldTypeMismatch if the type does not match, and may also abort with EBCSSerializationFailure.

public(friend) fun remove_child_object<Child: key>(parent: address, id: address): Child

Implementation

public(package) native fun remove_child_object<Child: key>(parent: address, id: address): Child;

Function has_child_object

public(friend) fun has_child_object(parent: address, id: address): bool

Implementation

public(package) native fun has_child_object(parent: address, id: address): bool;

Function has_child_object_with_ty

public(friend) fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool

Implementation

public(package) native fun has_child_object_with_ty<Child: key>(parent: address, id: address): bool;