Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hope to be supported by deserialization to the interface. #7

Open
ghost opened this issue Sep 12, 2017 · 7 comments
Open

Hope to be supported by deserialization to the interface. #7

ghost opened this issue Sep 12, 2017 · 7 comments

Comments

@ghost
Copy link

ghost commented Sep 12, 2017

Hope to be supported by deserialization to the interface.

Server and client communication Sometimes the server can not determine the type of the next packet of the client, this time want to support deserialization to the interface function, the Pack interface provides GetType () method to get the actual type and processing.

The current serialization is accompanied by the name of the structure, deserialization can be determined according to this should be deserialized to what structure.

I did not find a way to read the serialized structure name without loss, and it seems that in order to support deserialization to the structure, only the library itself can be modified.

example:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
)


type Pack interface {
	GetType() int
	String() string
}

type Pack1 struct {
	V1 string
}

func (p Pack1) GetType() int {
	return 1
}
func (p Pack1) String() string {
	return fmt.Sprintf("%#v", p)
}

type Pack2 struct {
	V2 string
}

func (p *Pack2) GetType() int {
	return 1
}
func (p *Pack2) String() string {
	return fmt.Sprintf("%#v", p)
}

func main() {
	gob.Register(Pack1{})
	gob.Register(&Pack2{})

	c := bytes.Buffer{}

	enc := gob.NewEncoder(&c)
	dec := gob.NewDecoder(&c)

	interfaceEncode(enc, Pack1{V1: "p1.v1:001"})

	p := interfaceDecode(dec)
	fmt.Println(p.GetType(), "\r\n", p)

	interfaceEncode(enc, &Pack2{V2: "p2.v2:001"})

	p = interfaceDecode(dec)
	fmt.Println(p.GetType(), "\r\n", p)
}

func interfaceEncode(enc *gob.Encoder, p Pack) {
	err := enc.Encode(&p)
	if err != nil {
		panic(err)
	}
}
func interfaceDecode(dec *gob.Decoder) Pack {
	var p Pack
	err := dec.Decode(&p)
	if err != nil {
		panic(err)
	}
	return p
}

@glycerine
Copy link
Owner

By default in zebrapack, all structs are written as msgpack maps and contain an additional field with the name of the struct as the value. The key is number -1 for that field. Search the generated code for the phrase "runtime struct type identification" and you'll see. This can be turned off with the flag -no-structnames-onwire, but it is on and available by default.

@ghost
Copy link
Author

ghost commented Sep 12, 2017

Yes, I see the 0xFF field has a structure name.
But if I read this field when the stream is deserialized, then UnmarshalMsg will not be able to read the ReadMapHeader and will not know the number of the structure's serialized fields.

Manually read the 0xFF can only manually read the field after the manual combination of structure, and this is very troublesome.

Server, client communication If the client can issue a variety of different request types, the server can not determine the deserialization of the structure type. Would like to ask this situation should be how to use better?
Send a byte to the structure type before sending the serialized structure?

@glycerine
Copy link
Owner

glycerine commented Sep 12, 2017

But if I read this field when the stream is deserialized, then UnmarshalMsg will not be able to read the ReadMapHeader and will not know the number of the structure's serialized fields.

This is incorrect. The -1 field is included in the map count.
https://github.com/glycerine/zebrapack/blob/master/gen/marshal.go#L122

@glycerine
Copy link
Owner

Send a byte to the structure type before sending the serialized structure?

Yes, typically one sends a header message that is always the same, and the header contains a message type indicator. The type indicator matches the message that follows.

@ghost
Copy link
Author

ghost commented Sep 13, 2017

Sorry, my English is no good. I mean the structure name field behind MapHeader, if my code would like to read the structure name field first read the MapHeader, so UnmarshalMsg can not work.

Is there any interest in increasing deserialization to interface {} function? I have time to try to add this two days.

Feel and gob similar to the realization of the way, pre-registered structure name, and then deserialization according to the name of the structure to generate the corresponding structure.
reflect can do this, but the label will lose performance.

Hardcuts can also be implemented by adding the init () function to x_gen.go, which registers its own deserialization interface with global variables.

The actual deserialization to interface {} can work like this:

  1. Read MapHeader first and get the number of fields
  2. Read the first -1 field and get the interface name
  3. Obtain the deserialization interface of the corresponding structure from the global variable according to the name
  4. Call the corresponding structure of the deserialization interface, the user provided interface {} passed in

You can also try to change the structure name int number of the way, should be able to save the transmission space and speed.

@glycerine
Copy link
Owner

glycerine commented Sep 13, 2017

I won't be able to work on this, but if you'd like to send a pull request, which must include tests of any new functionality, I will be happy to review it.

@glycerine glycerine reopened this Sep 13, 2017
@ghost
Copy link
Author

ghost commented Sep 22, 2017

Sorry, recently more busy.
After the busy I will try to add this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant