Skip to content

Commit d625bd9

Browse files
committed
Implement bytes() constructor
1 parent f72f347 commit d625bd9

File tree

1 file changed

+103
-1
lines changed

1 file changed

+103
-1
lines changed

py/bytes.go

+103-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,113 @@
22

33
package py
44

5-
var BytesType = NewType("bytes", "bytes(iterable_of_ints) -> bytes\nbytes(string, encoding[, errors]) -> bytes\nbytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\nbytes(int) -> bytes object of size given by the parameter initialized with null bytes\nbytes() -> empty bytes object\n\nConstruct an immutable array of bytes from:\n - an iterable yielding integers in range(256)\n - a text string encoded using the specified encoding\n - any object implementing the buffer API.\n - an integer")
5+
import (
6+
"strings"
7+
)
8+
9+
var BytesType = ObjectType.NewType("bytes",
10+
`bytes(iterable_of_ints) -> bytes
11+
bytes(string, encoding[, errors]) -> bytes
12+
bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer
13+
bytes(int) -> bytes object of size given by the parameter initialized with null bytes
14+
bytes() -> empty bytes object
15+
16+
Construct an immutable array of bytes from:
17+
- an iterable yielding integers in range(256)
18+
- a text string encoded using the specified encoding
19+
- any object implementing the buffer API.
20+
- an integer`, BytesNew, nil)
621

722
type Bytes []byte
823

924
// Type of this Bytes object
1025
func (o Bytes) Type() *Type {
1126
return BytesType
1227
}
28+
29+
// BytesNew
30+
func BytesNew(metatype *Type, args Tuple, kwargs StringDict) (res Object) {
31+
var x Object
32+
var encoding Object
33+
var errors Object
34+
var New Object
35+
kwlist := []string{"source", "encoding", "errors"}
36+
37+
ParseTupleAndKeywords(args, kwargs, "|Oss:bytes", kwlist, &x, &encoding, &errors)
38+
if x == nil {
39+
if encoding != nil || errors != nil {
40+
panic(ExceptionNewf(TypeError, "encoding or errors without sequence argument"))
41+
}
42+
return Bytes{}
43+
}
44+
45+
if s, ok := x.(String); ok {
46+
// Encode via the codec registry
47+
if encoding == nil {
48+
panic(ExceptionNewf(TypeError, "string argument without an encoding"))
49+
}
50+
encodingStr := strings.ToLower(string(encoding.(String)))
51+
if encodingStr == "utf-8" || encodingStr == "utf8" {
52+
return Bytes([]byte(s))
53+
}
54+
// FIXME
55+
// New = PyUnicode_AsEncodedString(x, encoding, errors)
56+
// assert(PyBytes_Check(New))
57+
// return New
58+
panic(ExceptionNewf(NotImplementedError, "String decode for %q not implemented", encodingStr))
59+
}
60+
61+
// We'd like to call PyObject_Bytes here, but we need to check for an
62+
// integer argument before deferring to PyBytes_FromObject, something
63+
// PyObject_Bytes doesn't do.
64+
var ok bool
65+
if I, ok := x.(I__bytes__); ok {
66+
New = I.M__bytes__()
67+
} else if New, ok = TypeCall0(x, "__bytes__"); ok {
68+
} else {
69+
goto no_bytes_method
70+
}
71+
if _, ok = New.(Bytes); !ok {
72+
panic(ExceptionNewf(TypeError, "__bytes__ returned non-bytes (type %s)", New.Type().Name))
73+
}
74+
no_bytes_method:
75+
76+
// Is it an integer?
77+
if _, ok := x.(Int); ok {
78+
size := IndexInt(x)
79+
if size < 0 {
80+
panic(ExceptionNewf(ValueError, "negative count"))
81+
}
82+
return make(Bytes, size)
83+
}
84+
85+
// If it's not unicode, there can't be encoding or errors
86+
if encoding != nil || errors != nil {
87+
panic(ExceptionNewf(TypeError, "encoding or errors without a string argument"))
88+
}
89+
90+
return BytesFromObject(x)
91+
}
92+
93+
// Converts an object into bytes
94+
func BytesFromObject(x Object) Bytes {
95+
// Look for special cases
96+
// FIXME implement converting from any object implementing the buffer API.
97+
switch z := x.(type) {
98+
case Bytes:
99+
// Immutable type so just return what was passed in
100+
return z
101+
case String:
102+
panic(ExceptionNewf(TypeError, "cannot convert unicode object to bytes"))
103+
}
104+
// Otherwise iterate through the whatever converting it into ints
105+
b := Bytes{}
106+
Iterate(x, func(item Object) {
107+
value := IndexInt(item)
108+
if value < 0 || value >= 256 {
109+
panic(ExceptionNewf(ValueError, "bytes must be in range(0, 256)"))
110+
}
111+
b = append(b, byte(value))
112+
})
113+
return b
114+
}

0 commit comments

Comments
 (0)