Skip to content

Commit

Permalink
Merge pull request #110 from xushiwei/t
Browse files Browse the repository at this point in the history
x/byteutil
  • Loading branch information
xushiwei authored Feb 25, 2024
2 parents 29f46cf + a134450 commit 3cf3f74
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 17 deletions.
21 changes: 20 additions & 1 deletion bytes/bytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,27 @@ import (

// ---------------------------------------------------

func TestBuffer(t *testing.T) {
func TestWriter(t *testing.T) {
b := make([]byte, 8)
w := NewWriter(b)
w.Write([]byte("abc"))
w.Write([]byte("1234567"))
if _, e := w.Write([]byte("A")); e != io.EOF {
t.Fatal("w.Write:", e)
}
if v := w.Len(); v != 8 {
t.Fatal("w.Len():", v)
}
if v := string(w.Bytes()); v != "abc12345" {
t.Fatal("w.Bytes():", v)
}
w.Reset()
if v := w.Len(); v != 0 {
t.Fatal("w.Len():", v)
}
}

func TestBuffer(t *testing.T) {
b := NewBuffer()
n, err := b.WriteStringAt("Hello", 4)
if n != 5 || err != nil {
Expand Down
31 changes: 31 additions & 0 deletions byteutil/bytes_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//go:build go1.21
// +build go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package byteutil

import (
"unsafe"
)

// Bytes returns a byte slice whose underlying data is s.
func Bytes(s string) []byte {
// Although unsafe.SliceData/String was introduced in go1.20, but
// the go version in go.mod is 1.18 so we cannot use them.
return unsafe.Slice(unsafe.StringData(s), len(s))
}
33 changes: 33 additions & 0 deletions byteutil/bytes_reflect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//go:build !go1.21
// +build !go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package byteutil

import (
"reflect"
"unsafe"
)

// Bytes returns a byte slice whose underlying data is s.
func Bytes(s string) (b []byte) {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return
}
15 changes: 9 additions & 6 deletions stringutil/string_mock.go → byteutil/bytes_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//go:build !go1.21
// +build !go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Expand All @@ -17,8 +14,14 @@
limitations under the License.
*/

package stringutil
package byteutil

import (
"testing"
)

func String(b []byte) string {
return string(b)
func TestBytes(t *testing.T) {
if b := Bytes("abc"); string(b) != "abc" {
t.Fatal("Bytes:", b)
}
}
31 changes: 22 additions & 9 deletions jsonutil/json_string.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
/*
Copyright 2019 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package jsonutil

import (
"encoding/json"
"reflect"
"unsafe"
)

// ----------------------------------------------------------
"github.com/qiniu/x/byteutil"
"github.com/qiniu/x/stringutil"
)

// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
func Unmarshal(data string, v interface{}) error {

sh := *(*reflect.StringHeader)(unsafe.Pointer(&data))
arr := (*[1 << 30]byte)(unsafe.Pointer(sh.Data))
return json.Unmarshal(arr[:sh.Len], v)
b := byteutil.Bytes(data)
return json.Unmarshal(b, v)
}

// ----------------------------------------------------------

// Stringify converts a value into string.
func Stringify(v interface{}) string {
b, _ := json.Marshal(v)
return string(b)
return stringutil.String(b)
}

// ----------------------------------------------------------
20 changes: 19 additions & 1 deletion jsonutil/json_string_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
/*
Copyright 2019 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package jsonutil

import (
"testing"
)

func Test(t *testing.T) {

var ret struct {
ID string `json:"id"`
}
Expand All @@ -16,4 +31,7 @@ func Test(t *testing.T) {
if ret.ID != "123" {
t.Fatal("Unmarshal uncorrect:", ret.ID)
}
if v := Stringify(ret); v != `{"id":"123"}` {
t.Fatal("Stringify:", v)
}
}
36 changes: 36 additions & 0 deletions stringutil/string_reflect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//go:build !go1.21
// +build !go1.21

/*
Copyright 2024 Qiniu Limited (qiniu.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package stringutil

import (
"reflect"
"unsafe"
)

// String returns a string value whose underlying bytes is b.
//
// Since Go strings are immutable, the bytes passed to String
// must not be modified afterwards.
func String(b []byte) (s string) {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := *(*reflect.SliceHeader)(unsafe.Pointer(&b))
sh.Data, sh.Len = bh.Data, bh.Len
return
}

0 comments on commit 3cf3f74

Please sign in to comment.