diff --git a/examples/sources/codegen/components/counter.move b/examples/sources/codegen/components/counter.move index 572773a8..cc55f279 100644 --- a/examples/sources/codegen/components/counter.move +++ b/examples/sources/codegen/components/counter.move @@ -1,34 +1,56 @@ -module examples::counter_component { - use examples::world::{Self , World}; - - // Systems +module examples::counter_comp { + use std::ascii::{String, string}; + use std::option::none; + use std::vector; + use sui::bcs; + use examples::entity_key; + use examples::world::{Self , World}; + + // Systems friend examples::counter_system; - - const COMPONENT_NAME: vector = b"Counter Component"; - - struct CounterData has drop, store { - value: u64 + + public fun id() : address { + entity_key::from_bytes(b"Examples Counter Comp") } - public fun new(value: u64): CounterData { - CounterData { - value - } + public fun field_types() : vector { + vector[string(b"u64")] } - public fun register(world: &mut World) { - world::add_component( + /// value: u64 + struct Field has drop, store { + data: vector + } + + public fun register(world: &mut World) { + world::add_component( world, - COMPONENT_NAME, - new(0) + id(), + Field { data: encode(10) } ); } - + public(friend) fun update(world: &mut World, value: u64) { - world::get_mut_component(world, COMPONENT_NAME).value = value; + let data = encode(value); + world::get_mut_component(world, id()).data = data; + world::emit_update_event(id(), none(), data) } public fun get(world: &World): u64 { - world::get_component(world, COMPONENT_NAME).value + let field = world::get_component(world, id()); + decode(field.data) + } + + public fun encode(value: u64): vector { + let data = vector::empty(); + vector::append(&mut data, bcs::to_bytes(&value)); + data + } + + public fun decode(bytes: vector): u64 { + let data = bcs::new(bytes); + ( + bcs::peel_u64(&mut data) + ) } } diff --git a/examples/sources/codegen/components/state.move b/examples/sources/codegen/components/state.move new file mode 100644 index 00000000..461bfae3 --- /dev/null +++ b/examples/sources/codegen/components/state.move @@ -0,0 +1,111 @@ +module examples::state_comp { + use std::ascii::{String, string}; + use std::option::some; + use std::vector; + use sui::bcs; + use sui::tx_context::TxContext; + use sui::table::{ Self, Table }; + use examples::entity_key; + use examples::world::{ Self , World }; + + public fun id() : address { + entity_key::from_bytes(b"Examples State Comp") + } + + public fun field_types() : vector { + vector[string(b"vector"), string(b"u64")] + } + + /// state: vector + /// last_update_time: u64 + struct Field has drop, store { + data: vector + } + + public fun register(world: &mut World, ctx: &mut TxContext) { + world::add_component>( + world, + id(), + table::new(ctx) + ); + } + + public(friend) fun add(world : &mut World, key: address, state: vector, last_update_time: u64) { + let component = world::get_mut_component>(world, id()); + let data = encode(state, last_update_time); + table::add(component, key, Field { data }); + world::emit_add_event(id(), key, data) + } + + public(friend) fun remove(world : &mut World, key: address) { + let component = world::get_mut_component>(world, id()); + table::remove(component, key); + world::emit_remove_event(id(), key) + } + + public(friend) fun update(world : &mut World, key: address, state: vector, last_update_time: u64) { + let component = world::get_mut_component>(world, id()); + let field = table::borrow_mut(component, key); + let data = encode(state, last_update_time); + field.data = data; + world::emit_update_event(id(), some(key), data) + } + + public(friend) fun update_state(world : &mut World, key: address, state: vector) { + let component = world::get_mut_component>(world, id()); + let field = table::borrow_mut(component, key); + let (_, last_update_time) = decode(field.data); + let data = encode(state, last_update_time); + field.data = data; + world::emit_update_event(id(), some(key), data) + } + + public(friend) fun update_last_update_time(world : &mut World, key: address, last_update_time: u64) { + let component = world::get_mut_component>(world, id()); + let field = table::borrow_mut(component, key); + let (state, _) = decode(field.data); + let data = encode(state, last_update_time); + field.data = data; + world::emit_update_event(id(), some(key), data) + } + + public fun get(world : &World, key: address) : (vector, u64) { + let component = world::get_component>(world, id()); + let field = table::borrow(component, key); + decode(field.data) + } + + public fun get_state(world : &World, key: address) : vector { + let component = world::get_component>(world, id()); + let field = table::borrow(component, key); + let (state,_) = decode(field.data); + state + } + + public fun get_last_update_time(world : &World, key: address) : u64 { + let component = world::get_component>(world, id()); + let field = table::borrow(component, key); + let (_,last_update_time) = decode(field.data); + last_update_time + } + + public fun contains(world : &World, key: address): bool { + let component = world::get_component>(world, id()); + table::contains(component, key) + } + + public fun encode(state: vector, last_update_time: u64): vector { + let data = vector::empty(); + vector::append(&mut data, bcs::to_bytes(&state)); + vector::append(&mut data, bcs::to_bytes(&last_update_time)); + data + } + + public fun decode(bytes: vector): (vector, u64) { + let data = bcs::new(bytes); + ( + bcs::peel_vec_u8(&mut data), + bcs::peel_u64(&mut data) + ) + } +} diff --git a/examples/sources/codegen/eps/world.move b/examples/sources/codegen/eps/world.move index 02ebf2bb..fd070df7 100644 --- a/examples/sources/codegen/eps/world.move +++ b/examples/sources/codegen/eps/world.move @@ -1,40 +1,82 @@ module examples::world { + use std::ascii::String; + use std::option::Option; + use sui::event; use sui::tx_context::TxContext; - use sui::hash::keccak256; use sui::bag::{ Self, Bag }; use sui::object::{ Self, UID }; + const CompDoesNotExist: u64 = 0; + const CompAlreadyExists: u64 = 1; + struct World has key, store{ id: UID, + /// Name of the world + name: String, + /// Description of the world + description: String, /// Components of the world - /// K256(component_name) <=> Table components: Bag, } - public fun create_world(ctx: &mut TxContext): World { + struct CompRemoveField has copy, drop { + comp: address, + key: address + } + + struct CompAddField has copy, drop { + comp: address, + key: address, + data: vector + } + + struct CompUpdateField has copy, drop { + comp: address, + key: Option
, + data: vector + } + + public fun create(name: String, description: String, ctx: &mut TxContext): World { World { id: object::new(ctx), + name, + description, components: bag::new(ctx), } } - public fun get_component(world: &World, component_name: vector): &T { - let component_id = keccak256(&component_name); - bag::borrow, T>(&world.components, component_id) + public fun info(world: &World): (String, String) { + (world.name, world.description) + } + + public fun get_component(world: &World, id: address): &T { + assert!(bag::contains(&world.components, id), CompDoesNotExist); + bag::borrow(&world.components, id) + } + + public fun get_mut_component(world: &mut World, id: address): &mut T { + assert!(bag::contains(&world.components, id), CompDoesNotExist); + bag::borrow_mut(&mut world.components, id) + } + + public fun add_component(world: &mut World, id: address, component: T){ + assert!(!bag::contains(&world.components, id), CompAlreadyExists); + bag::add(&mut world.components, id, component); + } + + public fun contains(world: &mut World, id: address): bool { + bag::contains(&mut world.components, id) } - public fun get_mut_component(world: &mut World, component_name: vector): &mut T { - let component_id = keccak256(&component_name); - bag::borrow_mut, T>(&mut world.components, component_id) + public fun emit_remove_event(comp: address, key: address) { + event::emit(CompRemoveField { comp, key }) } - public fun add_component(world: &mut World, component_name: vector, component: T){ - let component_id = keccak256(&component_name); - bag::add,T>(&mut world.components, component_id, component); + public fun emit_add_event(comp: address, key: address, data: vector) { + event::emit(CompAddField { comp, key, data}) } - public fun contains(world: &mut World, component_name: vector): bool { - let component_id = keccak256(&component_name); - bag::contains(&mut world.components, component_id) + public fun emit_update_event(comp: address, key: Option
, data: vector) { + event::emit(CompUpdateField { comp, key, data}) } } diff --git a/examples/sources/codegen/init.move b/examples/sources/codegen/init.move index 69daa5cb..b0b555eb 100644 --- a/examples/sources/codegen/init.move +++ b/examples/sources/codegen/init.move @@ -1,16 +1,16 @@ module examples::init { + use std::ascii::string; use sui::transfer; use sui::tx_context::TxContext; use examples::world; - use examples::counter_component; + use examples::counter_comp; fun init(ctx: &mut TxContext) { - let world = world::create_world(ctx); + let world = world::create(string(b"Examples Name"), string(b"Examples Description"),ctx); // Add Component - - counter_component::register(&mut world); + counter_comp::register(&mut world); transfer::public_share_object(world); } diff --git a/examples/sources/entity_key.move b/examples/sources/entity_key.move index b0d19ab3..b6e806ce 100644 --- a/examples/sources/entity_key.move +++ b/examples/sources/entity_key.move @@ -1,7 +1,38 @@ module examples::entity_key { + use std::vector; + use sui::address; use sui::object; - public fun object_to_entity_key(object: &T): vector { - object::id_bytes(object) + public fun from_object(object: &T): address { + object::id_address(object) + } + + public fun from_bytes(bytes: vector): address { + let len = vector::length(&bytes); + assert!(len != 0 && len <= 32, 0); + + let offset = address::length() - len; + + let i = 0; + while (i < offset) { + vector::push_back(&mut bytes,0u8); + i = i + 1; + }; + + address::from_bytes(bytes) + } + + public fun from_u256(x: u256): address { + address::from_u256(x) + } + + #[test] + public fun test_from_bytes() { + assert!(from_bytes(b"Hello") == @0x48656c6c6f000000000000000000000000000000000000000000000000000000, 0); + } + + #[test] + public fun test_from_u256() { + assert!(from_u256(1) == @0x1, 0); } } diff --git a/examples/sources/system/counter_system.move b/examples/sources/system/counter_system.move index eac18a1b..4ceddb16 100644 --- a/examples/sources/system/counter_system.move +++ b/examples/sources/system/counter_system.move @@ -1,10 +1,48 @@ module examples::counter_system { + use sui::tx_context::TxContext; use examples::world::World; - use examples::counter_component; + use examples::counter_comp; + #[test_only] + use std::ascii::string; + #[test_only] + use examples::init; + #[test_only] + use examples::world; + #[test_only] + use sui::test_scenario; - public entry fun increase(world: &mut World) { - let old_number = counter_component::get(world); + public entry fun increase(world: &mut World, _ctx: &mut TxContext) { + let old_number = counter_comp::get(world); let new_number = old_number + 1; - counter_component::update(world, new_number); + counter_comp::update(world, new_number); + } + + #[test] + public fun test_increase() { + let scenario_val = test_scenario::begin(@0x0001); + let scenario = &mut scenario_val; + { + let ctx = test_scenario::ctx(scenario); + init::init_world_for_testing(ctx); + }; + test_scenario::next_tx(scenario,@0x0001); + let world = test_scenario::take_shared(scenario); + + let (name,description) = world::info(&world); + + assert!(name == string(b"Examples Name"), 0); + assert!(description == string(b"Examples Description"), 0); + { + let ctx = test_scenario::ctx(scenario); + increase(&mut world, ctx); + }; + test_scenario::next_tx(scenario,@0x0001); + + assert!(counter_comp::get(&world) == 11, 0); + + test_scenario::return_shared(world); + test_scenario::end(scenario_val); } } + +