package core import ( "errors" "github.com/dop251/goja" ) func Buffer(vm *goja.Runtime, call goja.ConstructorCall) *goja.Object { var buffer []byte switch arg := call.Arguments[0].Export().(type) { case string: buffer = []byte(arg) case []byte: buffer = arg case int: buffer = make([]byte, arg) case int64: buffer = make([]byte, arg) default: panic(vm.NewTypeError("invalid argument type")) } obj := call.This.ToObject(vm) obj.Set("length", func() int { return len(buffer) }) obj.Set("write", func(value interface{}, offset int, length int) { var buf []byte switch value := value.(type) { case string: buf = []byte(value) case []byte: buf = value default: panic(vm.NewTypeError("invalid argument type")) } if offset+length > len(buffer) { panic(vm.NewGoError(errors.New("out of range"))) } copy(buffer[offset:], buf[:length]) }) obj.Set("toString", func() string { return string(buffer) }) obj.Set("slice", func(start int, end int) []byte { if start < 0 { start += len(buffer) } if end < 0 { end += len(buffer) } if end > len(buffer) { end = len(buffer) } if start >= end || start >= len(buffer) { return nil } return buffer[start:end] }) obj.Set("copy", func(target []byte, sourceStart int, targetStart int, sourceEnd int) int { if sourceStart < 0 { sourceStart += len(buffer) } if sourceEnd < 0 { sourceEnd += len(buffer) } if targetStart < 0 { targetStart += len(target) } if sourceEnd > len(buffer) { sourceEnd = len(buffer) } if sourceStart >= sourceEnd || sourceStart >= len(buffer) { return 0 } return copy(target[targetStart:], buffer[sourceStart:sourceEnd]) }) obj.Set("join", func(sep []byte, buffers ...[]byte) []byte { var totalLen int for _, buf := range buffers { totalLen += len(buf) } if len(sep) > 0 && len(buffers) > 1 { totalLen += len(sep) * (len(buffers) - 1) } result := make([]byte, totalLen) offset := 0 for i, buf := range buffers { copy(result[offset:], buf) offset += len(buf) if i < len(buffers)-1 && len(sep) > 0 { copy(result[offset:], sep) offset += len(sep) } } return result }) return call.This }