arrow/extensions/bool8.go (159 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you 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 extensions import ( "fmt" "reflect" "strconv" "strings" "unsafe" "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/memory" "github.com/apache/arrow-go/v18/internal/json" ) // Bool8Type represents a logical boolean that is stored using 8 bits. type Bool8Type struct { arrow.ExtensionBase } // NewBool8Type creates a new Bool8Type with the underlying storage type set correctly to Int8. func NewBool8Type() *Bool8Type { return &Bool8Type{ExtensionBase: arrow.ExtensionBase{Storage: arrow.PrimitiveTypes.Int8}} } func (b *Bool8Type) ArrayType() reflect.Type { return reflect.TypeOf(Bool8Array{}) } func (b *Bool8Type) Deserialize(storageType arrow.DataType, data string) (arrow.ExtensionType, error) { if !arrow.TypeEqual(storageType, arrow.PrimitiveTypes.Int8) { return nil, fmt.Errorf("invalid storage type for Bool8Type: %s", storageType.Name()) } return NewBool8Type(), nil } func (b *Bool8Type) ExtensionEquals(other arrow.ExtensionType) bool { return b.ExtensionName() == other.ExtensionName() } func (b *Bool8Type) ExtensionName() string { return "arrow.bool8" } func (b *Bool8Type) Serialize() string { return "" } func (b *Bool8Type) String() string { return fmt.Sprintf("extension<%s>", b.ExtensionName()) } func (*Bool8Type) NewBuilder(mem memory.Allocator) array.Builder { return NewBool8Builder(mem) } // Bool8Array is logically an array of boolean values but uses // 8 bits to store values instead of 1 bit as in the native BooleanArray. type Bool8Array struct { array.ExtensionArrayBase } func (a *Bool8Array) String() string { var o strings.Builder o.WriteString("[") for i := 0; i < a.Len(); i++ { if i > 0 { o.WriteString(" ") } switch { case a.IsNull(i): o.WriteString(array.NullValueStr) default: fmt.Fprintf(&o, "%v", a.Value(i)) } } o.WriteString("]") return o.String() } func (a *Bool8Array) Value(i int) bool { return a.Storage().(*array.Int8).Value(i) != 0 } func (a *Bool8Array) BoolValues() []bool { int8s := a.Storage().(*array.Int8).Int8Values() return unsafe.Slice((*bool)(unsafe.Pointer(unsafe.SliceData(int8s))), len(int8s)) } func (a *Bool8Array) ValueStr(i int) string { switch { case a.IsNull(i): return array.NullValueStr default: return fmt.Sprint(a.Value(i)) } } func (a *Bool8Array) MarshalJSON() ([]byte, error) { values := make([]interface{}, a.Len()) for i := 0; i < a.Len(); i++ { if a.IsValid(i) { values[i] = a.Value(i) } } return json.Marshal(values) } func (a *Bool8Array) GetOneForMarshal(i int) interface{} { if a.IsNull(i) { return nil } return a.Value(i) } // boolToInt8 performs the simple scalar conversion of bool to the canonical int8 // value for the Bool8Type. func boolToInt8(v bool) int8 { var res int8 if v { res = 1 } return res } // Bool8Builder is a convenience builder for the Bool8 extension type, // allowing arrays to be built with boolean values rather than the underlying storage type. type Bool8Builder struct { *array.ExtensionBuilder } // NewBool8Builder creates a new Bool8Builder, exposing a convenient and efficient interface // for writing boolean values to the underlying int8 storage array. func NewBool8Builder(mem memory.Allocator) *Bool8Builder { return &Bool8Builder{ExtensionBuilder: array.NewExtensionBuilder(mem, NewBool8Type())} } func (b *Bool8Builder) Append(v bool) { b.ExtensionBuilder.Builder.(*array.Int8Builder).Append(boolToInt8(v)) } func (b *Bool8Builder) UnsafeAppend(v bool) { b.ExtensionBuilder.Builder.(*array.Int8Builder).UnsafeAppend(boolToInt8(v)) } func (b *Bool8Builder) AppendValueFromString(s string) error { if s == array.NullValueStr { b.AppendNull() return nil } val, err := strconv.ParseBool(s) if err != nil { return err } b.Append(val) return nil } func (b *Bool8Builder) AppendValues(v []bool, valid []bool) { boolsAsInt8s := unsafe.Slice((*int8)(unsafe.Pointer(unsafe.SliceData(v))), len(v)) b.ExtensionBuilder.Builder.(*array.Int8Builder).AppendValues(boolsAsInt8s, valid) } func (b *Bool8Builder) UnmarshalOne(dec *json.Decoder) error { t, err := dec.Token() if err != nil { return err } switch v := t.(type) { case bool: b.Append(v) return nil case string: return b.AppendValueFromString(v) case int8: b.ExtensionBuilder.Builder.(*array.Int8Builder).Append(v) return nil case nil: b.AppendNull() return nil default: return &json.UnmarshalTypeError{ Value: fmt.Sprint(t), Type: reflect.TypeOf([]byte{}), Offset: dec.InputOffset(), Struct: "Bool8Builder", } } } func (b *Bool8Builder) Unmarshal(dec *json.Decoder) error { for dec.More() { if err := b.UnmarshalOne(dec); err != nil { return err } } return nil } var ( _ arrow.ExtensionType = (*Bool8Type)(nil) _ array.CustomExtensionBuilder = (*Bool8Type)(nil) _ array.ExtensionArray = (*Bool8Array)(nil) _ array.Builder = (*Bool8Builder)(nil) )