oniksan / godobuf

A Google Protobuf implementation for Godot / GDScript
BSD 3-Clause "New" or "Revised" License
260 stars 36 forks source link

Allow deepcopy of messages #19

Closed videlanicolas closed 3 years ago

videlanicolas commented 3 years ago

Following #9, consider the following example:

message GiantSlime {}
message PettySlime {}
message MagicOrc {}
message NormalOrc {}

message Slime {
    oneof type_of_slime {
        GiantSlime giant_slime = 1;
        PettySlime petty_slime = 2;
    }
}

message Orc {
    oneof type_of_orc {
        MagicOrc magic_orc = 1;
        NormalOrc normal_orc = 2;
    }
}

message Enemy {
    oneof type_of_enemy {
        Slime slime = 1;
        Orc orc = 2;
    }
}

If one has the following function in GD Script:

const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
    var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
    var orc:MyProto.Orc = spawn_enemy.new_orc()
    orc = spawn_orc
    return spawn_enemy

spawn_enemy will not contain a copy of spawn_orc, but will instead be empty. The user would have to call the individual set_ function for each property, but will encounter that for composite properties that are defined by messages (like the one in this example) they'll have to initialise a new object and "set" it with the data that comes from spawn_orc.

The API could provide a function to "deepcopy" one proto into another, thus avoiding the need of going each property one by one and setting it to the correct value. An example would be:

const MyProto = preload("res://proto/myproto.gd")
....
func SpawnOrc(spawn_orc:MyProto.Orc) -> MyProto.Enemy:
    var spawn_enemy:MyProto.Enemy = MyProto.Enemy.new()
    var orc:MyProto.Orc = spawn_enemy.new_orc()
    orc.deepcopy(spawn_orc)
    return spawn_enemy
oniksan commented 3 years ago

If I understand correctly, you are trying to portray inheritance by means of a protocol, which is not intended for this. Oneof it's one of unrelated objects.

message GiantSlime {}
message MagicOrc {}

message Slime {
    oneof type_of_slime {
        GiantSlime giant_slime = 1;
        string only_string = 2;
    }
}

message Orc {
    oneof type_of_orc {
        MagicOrc magic_orc = 1;
        sint32 simple_int = 2;
    }
}

message Enemy {
    oneof type_of_enemy {
        Slime slime = 1;
        Orc orc = 2;
        float dog_tail_length = 3;
    }
}

What we need to do??

videlanicolas commented 3 years ago

Perhaps I'm thinking this the wrong way, what I need instead is a library in GD Script that aids protobufs, something like this (in Golang). That way I can have help functions that are common to any protobuf, such as: Merge, DeepCopy, Equals. Would this be the solution here?

oniksan commented 3 years ago

I'm not sure... Right now I have very little time to do this project. Moreover, it is necessary to consider in detail the need for each implemented solution.

videlanicolas commented 3 years ago

Writing this comment for future users that want a similar implementation. I've found a way of doing a deepcopy of one message to another, and is rather simple.

func Deepcopy(from, to):
    to.from_bytes(from.to_bytes())

Given that is short and simple, I don't think we need an extra library to implement this.

Nevertheless there might be more complicated functions that could be needed in the future. Some examples are:

Closing this bug since the question has been answered and there' s no need to add a feature.