pk.Ary and pk.Array using generic now
This commit is contained in:
@ -109,7 +109,6 @@ func ExamplePacket_Scan_joinGame() {
|
||||
Hardcore pk.Boolean
|
||||
Gamemode pk.UnsignedByte
|
||||
PreGamemode pk.Byte
|
||||
WorldCount pk.VarInt
|
||||
WorldNames = make([]pk.Identifier, 0) // This cannot replace with "var WorldNames []pk.Identifier" because "nil" has no type information
|
||||
DimensionCodec struct {
|
||||
DimensionType interface{} `nbt:"minecraft:dimension_type"`
|
||||
@ -127,9 +126,7 @@ func ExamplePacket_Scan_joinGame() {
|
||||
&Hardcore,
|
||||
&Gamemode,
|
||||
&PreGamemode,
|
||||
&WorldCount,
|
||||
pk.Ary{
|
||||
Len: &WorldCount,
|
||||
pk.Ary[pk.VarInt, *pk.VarInt]{
|
||||
Ary: &WorldNames,
|
||||
},
|
||||
pk.NBT(&DimensionCodec),
|
||||
|
@ -17,20 +17,29 @@ import (
|
||||
// In some special cases, you might want to read an "Array of X" with a fix length.
|
||||
// So it's allowed to directly set an integer type Len, but not a pointer.
|
||||
//
|
||||
// Note that Ary DO NOT read or write the Len. You are controlling it manually.
|
||||
type Ary struct {
|
||||
Len interface{} // Value or Pointer of any integer type, only needed in ReadFrom
|
||||
// Note that Ary DO read or write the Len. You aren't need to do so by your self.
|
||||
type Ary[T VarInt | VarLong | Byte | UnsignedByte | Short | UnsignedShort | Int | Long, L interface {
|
||||
*T
|
||||
ReadFrom(r io.Reader) (n int64, err error)
|
||||
WriteTo(w io.Writer) (n int64, err error)
|
||||
}] struct {
|
||||
Ary interface{} // Slice or Pointer of Slice of FieldEncoder, FieldDecoder or both (Field)
|
||||
}
|
||||
|
||||
func (a Ary) WriteTo(r io.Writer) (n int64, err error) {
|
||||
func (a Ary[T, L]) WriteTo(w io.Writer) (n int64, err error) {
|
||||
array := reflect.ValueOf(a.Ary)
|
||||
for array.Kind() == reflect.Ptr {
|
||||
array = array.Elem()
|
||||
}
|
||||
Len := T(array.Len())
|
||||
if nn, err := L(&Len).WriteTo(w); err != nil {
|
||||
return n, err
|
||||
} else {
|
||||
n += nn
|
||||
}
|
||||
for i := 0; i < array.Len(); i++ {
|
||||
elem := array.Index(i)
|
||||
nn, err := elem.Interface().(FieldEncoder).WriteTo(r)
|
||||
nn, err := elem.Interface().(FieldEncoder).WriteTo(w)
|
||||
n += nn
|
||||
if err != nil {
|
||||
return n, err
|
||||
@ -39,24 +48,14 @@ func (a Ary) WriteTo(r io.Writer) (n int64, err error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (a Ary) length() int {
|
||||
v := reflect.ValueOf(a.Len)
|
||||
for {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
v = v.Elem()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return int(v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return int(v.Uint())
|
||||
default:
|
||||
panic(errors.New("unsupported Len value: " + v.Type().String()))
|
||||
}
|
||||
func (a Ary[T, L]) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
var Len T
|
||||
if nn, err := L(&Len).ReadFrom(r); err != nil {
|
||||
return nn, err
|
||||
} else {
|
||||
n += nn
|
||||
}
|
||||
}
|
||||
|
||||
func (a Ary) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
length := a.length()
|
||||
array := reflect.ValueOf(a.Ary)
|
||||
for array.Kind() == reflect.Ptr {
|
||||
array = array.Elem()
|
||||
@ -64,10 +63,12 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
if !array.CanAddr() {
|
||||
panic(errors.New("the contents of the Ary are not addressable"))
|
||||
}
|
||||
if array.Cap() < length {
|
||||
array.Set(reflect.MakeSlice(array.Type(), length, length))
|
||||
if array.Cap() < int(Len) {
|
||||
array.Set(reflect.MakeSlice(array.Type(), int(Len), int(Len)))
|
||||
} else {
|
||||
array.Slice(0, int(Len))
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
for i := 0; i < int(Len); i++ {
|
||||
elem := array.Index(i)
|
||||
nn, err := elem.Addr().Interface().(FieldDecoder).ReadFrom(r)
|
||||
n += nn
|
||||
@ -78,27 +79,8 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Array return an Ary but handled the previous Length field
|
||||
//
|
||||
// Warning: unstable API, may change in later version
|
||||
func Array(array interface{}) Field {
|
||||
var length VarInt
|
||||
|
||||
value := reflect.ValueOf(array)
|
||||
for value.Kind() == reflect.Ptr {
|
||||
value = value.Elem()
|
||||
}
|
||||
|
||||
if array != nil {
|
||||
length = VarInt(value.Len())
|
||||
}
|
||||
return Tuple{
|
||||
&length,
|
||||
Ary{
|
||||
Len: &length,
|
||||
Ary: array,
|
||||
},
|
||||
}
|
||||
func Array(ary interface{}) Field {
|
||||
return Ary[VarInt, *VarInt]{Ary: ary}
|
||||
}
|
||||
|
||||
type Opt struct {
|
||||
|
@ -13,28 +13,18 @@ func ExampleAry_WriteTo() {
|
||||
// The length is inferred from the length of Ary.
|
||||
pk.Marshal(
|
||||
0x00,
|
||||
// It's important to remember that
|
||||
// typically the responsibility of
|
||||
// sending the length field
|
||||
// is on you.
|
||||
pk.VarInt(len(data)),
|
||||
pk.Ary{
|
||||
Len: len(data), // this line can be removed
|
||||
pk.Ary[pk.VarInt, *pk.VarInt]{
|
||||
Ary: data,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func ExampleAry_ReadFrom() {
|
||||
var length pk.VarInt
|
||||
var data []pk.String
|
||||
|
||||
var p pk.Packet // = conn.ReadPacket()
|
||||
if err := p.Scan(
|
||||
|
||||
&length, // decode length first
|
||||
pk.Ary{ // then decode Ary according to length
|
||||
Len: &length,
|
||||
pk.Ary[pk.VarInt, *pk.VarInt]{ // then decode Ary according to length
|
||||
Ary: &data,
|
||||
},
|
||||
); err != nil {
|
||||
@ -43,18 +33,18 @@ func ExampleAry_ReadFrom() {
|
||||
}
|
||||
|
||||
func TestAry_ReadFrom(t *testing.T) {
|
||||
var num pk.Int = 2
|
||||
var ary []pk.String
|
||||
var bin = []byte{
|
||||
0, 0, 0, 2,
|
||||
4, 'T', 'n', 'z', 'e',
|
||||
0,
|
||||
}
|
||||
var data = pk.Ary{Len: &num, Ary: &ary}
|
||||
var data = pk.Ary[pk.Int, *pk.Int]{Ary: &ary}
|
||||
if _, err := data.ReadFrom(bytes.NewReader(bin)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ary) != int(num) {
|
||||
t.Fatalf("length not match: %d != %d", len(ary), num)
|
||||
if len(ary) != 2 {
|
||||
t.Fatalf("length not match: %d != %d", len(ary), 2)
|
||||
}
|
||||
for i, v := range []string{"Tnze", ""} {
|
||||
if string(ary[i]) != v {
|
||||
@ -70,23 +60,22 @@ func TestAry_WriteTo(t *testing.T) {
|
||||
0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03,
|
||||
}
|
||||
int3, long3, varint3, varlong3 := pk.Int(3), pk.Long(3), pk.VarInt(3), pk.VarLong(3)
|
||||
for _, item := range [...]pk.Ary{
|
||||
{Len: 3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: int3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: long3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: varint3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: varlong3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: &int3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: &long3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: &varint3, Ary: []pk.Int{1, 2, 3}},
|
||||
{Len: &varlong3, Ary: []pk.Int{1, 2, 3}},
|
||||
for _, item := range [...]pk.FieldEncoder{
|
||||
pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.Long, *pk.Long]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.VarInt, *pk.VarInt]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.VarLong, *pk.VarLong]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.Int, *pk.Int]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.Long, *pk.Long]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.VarInt, *pk.VarInt]{Ary: []pk.Int{1, 2, 3}},
|
||||
pk.Ary[pk.VarLong, *pk.VarLong]{Ary: []pk.Int{1, 2, 3}},
|
||||
} {
|
||||
_, err := item.WriteTo(&buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(buf.Bytes(), want) {
|
||||
if !bytes.Equal(buf.Bytes()[buf.Len()-3*4:], want) {
|
||||
t.Fatalf("Ary encoding error: got %#v, want %#v", buf.Bytes(), want)
|
||||
}
|
||||
buf.Reset()
|
||||
@ -96,11 +85,12 @@ func TestAry_WriteTo(t *testing.T) {
|
||||
func TestAry_WriteTo_pointer(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
want := []byte{
|
||||
0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x02,
|
||||
0x00, 0x00, 0x00, 0x03,
|
||||
}
|
||||
data := pk.Ary{Ary: &[]pk.Int{1, 2, 3}}
|
||||
data := pk.Ary[pk.Int, *pk.Int]{Ary: &[]pk.Int{1, 2, 3}}
|
||||
|
||||
_, err := data.WriteTo(&buf)
|
||||
if err != nil {
|
||||
@ -184,7 +174,6 @@ func ExampleOpt_ReadFrom_func() {
|
||||
func ExampleTuple_ReadFrom() {
|
||||
// When you need to read an "Optional Array of X":
|
||||
var has pk.Boolean
|
||||
var arylen pk.Int
|
||||
var ary []pk.String
|
||||
|
||||
var p pk.Packet // = conn.ReadPacket()
|
||||
@ -193,9 +182,7 @@ func ExampleTuple_ReadFrom() {
|
||||
pk.Opt{
|
||||
Has: &has,
|
||||
Field: pk.Tuple{
|
||||
&arylen,
|
||||
pk.Ary{
|
||||
Len: &arylen,
|
||||
pk.Ary[pk.Int, *pk.Int]{
|
||||
Ary: &ary,
|
||||
},
|
||||
},
|
||||
|
Reference in New Issue
Block a user