Module iota::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 iota::address;
use iota::hex;
use iota::object;
use iota::tx_context;
use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::vector;
Module Functions
pub 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 iota::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)
}
pub 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: &iota::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
}
pub 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 iota::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
}
pub 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: &iota::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)
}
pub 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: &iota::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)
}
pub 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 iota::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
}
pub 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 iota::object::UID, name: Name): std::option::Option<Value>
Implementation
pub(pkg) add_child_object
public(package) fun add_child_object<Child: key>(parent: address, child: Child)
Implementation
public(package) native fun add_child_object<Child: key>(parent: address, child: Child);
pub(pkg) 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(package) fun borrow_child_object<Child: key>(object: &iota::object::UID, id: address): &Child
Implementation
public(package) native fun borrow_child_object<Child: key>(object: &UID, id: address): &Child;
pub(pkg) borrow_child_object_mut
public(package) fun borrow_child_object_mut<Child: key>(object: &mut iota::object::UID, id: address): &mut Child
Implementation
public(package) native fun borrow_child_object_mut<Child: key>(
object: &mut UID,
id: address,
): &mut Child;
pub(pkg) field_info
public(package) fun field_info<Name: copy, drop, store>(object: &iota::object::UID, name: Name): (&iota::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())
}
pub(pkg) field_info_mut
public(package) fun field_info_mut<Name: copy, drop, store>(object: &mut iota::object::UID, name: Name): (&mut iota::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())
}
pub(pkg) has_child_object
public(package) fun has_child_object(parent: address, id: address): bool
Implementation
public(package) native fun has_child_object(parent: address, id: address): bool;
pub(pkg) has_child_object_with_ty
public(package) 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;
pub(pkg) hash_type_and_key
May abort with EBCSSerializationFailure.
public(package) 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;
pub(pkg) 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(package) 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;
Structs
struct Field
Internal object used for storing the field and value
public struct Field<Name: copy, drop, store, Value: store> has key
Fields
id: iota::object::UIDDetermined by the hash of the object ID, the field name value and it's type, i.e. hash(parent.id || name || Name)
name: NameThe value for the name of this field
value: ValueThe value bound to this field
Constants
err EFieldAlreadyExists
The object already has a dynamic field with this name (with the value and type specified)
const EFieldAlreadyExists: u64 = 0;
err EFieldDoesNotExist
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;
err EFieldTypeMismatch
The object has a field with that name, but the value type does not match
const EFieldTypeMismatch: u64 = 2;
err EBCSSerializationFailure
Failed to serialize the field's name
const EBCSSerializationFailure: u64 = 3;
err ESharedObjectOperationNotSupported
The object added as a dynamic field was previously a shared object
const ESharedObjectOperationNotSupported: u64 = 4;