github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/bytearray.go (about) 1 // Copyright 2017 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "bytes" 19 "fmt" 20 "reflect" 21 "sync" 22 ) 23 24 var ( 25 // ByteArrayType is the object representing the Python 'bytearray' type. 26 ByteArrayType = newBasisType("bytearray", reflect.TypeOf(ByteArray{}), toByteArrayUnsafe, ObjectType) 27 ) 28 29 // ByteArray represents Python 'bytearray' objects. 30 type ByteArray struct { 31 Object 32 mutex sync.RWMutex 33 value []byte 34 } 35 36 func toByteArrayUnsafe(o *Object) *ByteArray { 37 return (*ByteArray)(o.toPointer()) 38 } 39 40 // ToObject upcasts a to an Object. 41 func (a *ByteArray) ToObject() *Object { 42 return &a.Object 43 } 44 45 // Value returns the underlying bytes held by a. 46 func (a *ByteArray) Value() []byte { 47 return a.value 48 } 49 50 func byteArrayEq(f *Frame, v, w *Object) (*Object, *BaseException) { 51 return byteArrayCompare(v, w, False, True, False), nil 52 } 53 54 func byteArrayGE(f *Frame, v, w *Object) (*Object, *BaseException) { 55 return byteArrayCompare(v, w, False, True, True), nil 56 } 57 58 func byteArrayGetItem(f *Frame, o, key *Object) (result *Object, raised *BaseException) { 59 a := toByteArrayUnsafe(o) 60 if key.typ.slots.Index != nil { 61 index, raised := IndexInt(f, key) 62 if raised != nil { 63 return nil, raised 64 } 65 a.mutex.RLock() 66 elems := a.Value() 67 if index, raised = seqCheckedIndex(f, len(elems), index); raised == nil { 68 result = NewInt(int(elems[index])).ToObject() 69 } 70 a.mutex.RUnlock() 71 return result, raised 72 } 73 if key.isInstance(SliceType) { 74 a.mutex.RLock() 75 elems := a.Value() 76 start, stop, step, sliceLen, raised := toSliceUnsafe(key).calcSlice(f, len(elems)) 77 if raised == nil { 78 value := make([]byte, sliceLen) 79 if step == 1 { 80 copy(value, elems[start:stop]) 81 } else { 82 i := 0 83 for j := start; j != stop; j += step { 84 value[i] = elems[j] 85 i++ 86 } 87 } 88 result = (&ByteArray{Object: Object{typ: ByteArrayType}, value: value}).ToObject() 89 } 90 a.mutex.RUnlock() 91 return result, raised 92 } 93 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("bytearray indices must be integers or slice, not %s", key.typ.Name())) 94 } 95 96 func byteArrayGT(f *Frame, v, w *Object) (*Object, *BaseException) { 97 return byteArrayCompare(v, w, False, False, True), nil 98 } 99 100 func byteArrayInit(f *Frame, o *Object, args Args, _ KWArgs) (*Object, *BaseException) { 101 argc := len(args) 102 if argc == 0 { 103 return None, nil 104 } 105 expectedTypes := []*Type{ObjectType} 106 if raised := checkFunctionArgs(f, "__init__", args, expectedTypes...); raised != nil { 107 return nil, raised 108 } 109 a := toByteArrayUnsafe(o) 110 if args[0].isInstance(IntType) { 111 a.mutex.Lock() 112 a.value = make([]byte, toIntUnsafe(args[0]).Value()) 113 a.mutex.Unlock() 114 return None, nil 115 } 116 // else it must be an iterable 117 value := []byte{} 118 iter, raised := Iter(f, args[0]) 119 if raised != nil { 120 return nil, raised 121 } 122 item, raised := Next(f, iter) 123 for ; raised == nil; item, raised = Next(f, iter) { 124 switch { 125 case item.isInstance(StrType): 126 sval := toStrUnsafe(item).Value() 127 if len(sval) != 1 { 128 return nil, f.RaiseType(ValueErrorType, "string must be of size 1") 129 } 130 value = append(value, sval[0]) 131 case item.isInstance(IntType): 132 ival := toIntUnsafe(item).Value() 133 if ival < 0 || ival >= 256 { 134 return nil, f.RaiseType(ValueErrorType, "byte must be in range(0, 256)") 135 } 136 value = append(value, byte(ival)) 137 default: 138 return nil, f.RaiseType(TypeErrorType, "an integer or string of size 1 is required") 139 } 140 } 141 if !raised.isInstance(StopIterationType) { 142 return nil, raised 143 } 144 f.RestoreExc(nil, nil) 145 a.mutex.Lock() 146 a.value = value 147 a.mutex.Unlock() 148 return None, nil 149 } 150 151 func byteArrayLE(f *Frame, v, w *Object) (*Object, *BaseException) { 152 return byteArrayCompare(v, w, True, True, False), nil 153 } 154 155 func byteArrayLT(f *Frame, v, w *Object) (*Object, *BaseException) { 156 return byteArrayCompare(v, w, True, False, False), nil 157 } 158 159 func byteArrayNative(f *Frame, o *Object) (reflect.Value, *BaseException) { 160 a := toByteArrayUnsafe(o) 161 a.mutex.RLock() 162 result := reflect.ValueOf(a.Value()) 163 a.mutex.RUnlock() 164 return result, nil 165 } 166 167 func byteArrayNE(f *Frame, v, w *Object) (*Object, *BaseException) { 168 return byteArrayCompare(v, w, True, False, True), nil 169 } 170 171 func byteArrayRepr(f *Frame, o *Object) (*Object, *BaseException) { 172 a := toByteArrayUnsafe(o) 173 a.mutex.RLock() 174 s, raised := Repr(f, NewStr(string(a.Value())).ToObject()) 175 a.mutex.RUnlock() 176 if raised != nil { 177 return nil, raised 178 } 179 return NewStr(fmt.Sprintf("bytearray(b%s)", s.Value())).ToObject(), nil 180 } 181 182 func byteArrayStr(f *Frame, o *Object) (*Object, *BaseException) { 183 a := toByteArrayUnsafe(o) 184 a.mutex.RLock() 185 s := string(a.Value()) 186 a.mutex.RUnlock() 187 return NewStr(s).ToObject(), nil 188 } 189 190 func initByteArrayType(dict map[string]*Object) { 191 ByteArrayType.slots.Eq = &binaryOpSlot{byteArrayEq} 192 ByteArrayType.slots.GE = &binaryOpSlot{byteArrayGE} 193 ByteArrayType.slots.GetItem = &binaryOpSlot{byteArrayGetItem} 194 ByteArrayType.slots.GT = &binaryOpSlot{byteArrayGT} 195 ByteArrayType.slots.Init = &initSlot{byteArrayInit} 196 ByteArrayType.slots.LE = &binaryOpSlot{byteArrayLE} 197 ByteArrayType.slots.LT = &binaryOpSlot{byteArrayLT} 198 ByteArrayType.slots.Native = &nativeSlot{byteArrayNative} 199 ByteArrayType.slots.NE = &binaryOpSlot{byteArrayNE} 200 ByteArrayType.slots.Repr = &unaryOpSlot{byteArrayRepr} 201 ByteArrayType.slots.Str = &unaryOpSlot{byteArrayStr} 202 } 203 204 func byteArrayCompare(v, w *Object, ltResult, eqResult, gtResult *Int) *Object { 205 if v == w { 206 return eqResult.ToObject() 207 } 208 // For simplicity we make a copy of w if it's a str or bytearray. This 209 // is inefficient and it may be useful to optimize. 210 var data []byte 211 switch { 212 case w.isInstance(StrType): 213 data = []byte(toStrUnsafe(w).Value()) 214 case w.isInstance(ByteArrayType): 215 a := toByteArrayUnsafe(w) 216 a.mutex.RLock() 217 data = make([]byte, len(a.value)) 218 copy(data, a.value) 219 a.mutex.RUnlock() 220 default: 221 return NotImplemented 222 } 223 a := toByteArrayUnsafe(v) 224 a.mutex.RLock() 225 cmp := bytes.Compare(a.value, data) 226 a.mutex.RUnlock() 227 switch cmp { 228 case -1: 229 return ltResult.ToObject() 230 case 0: 231 return eqResult.ToObject() 232 default: 233 return gtResult.ToObject() 234 } 235 }