diff --git a/src/arraytypes/fixedsizelist.jl b/src/arraytypes/fixedsizelist.jl index 9393049a..d032299b 100644 --- a/src/arraytypes/fixedsizelist.jl +++ b/src/arraytypes/fixedsizelist.jl @@ -31,15 +31,29 @@ Base.size(l::FixedSizeList) = (l.ℓ,) @propagate_inbounds function Base.getindex(l::FixedSizeList{T}, i::Integer) where {T} @boundscheck checkbounds(l, i) - N = ArrowTypes.getsize(Base.nonmissingtype(T)) - off = (i - 1) * N - if Base.nonmissingtype(T) !== T - return l.validity[i] ? ArrowTypes.arrowconvert(T, ntuple(j->l.data[off + j], N)) : missing + X = Base.nonmissingtype(T) + N = ArrowTypes.getsize(X) + Y = ArrowTypes.gettype(X) + if X !== T && !(l.validity[i]) + return missing else - return ArrowTypes.arrowconvert(T, ntuple(j->l.data[off + j], N)) + off = (i - 1) * N + if X === T && isbitstype(Y) + tup = _unsafe_load_tuple(NTuple{N,Y}, l.data, off + 1) + else + tup = ntuple(j->l.data[off + j], N) + end + return ArrowTypes.arrowconvert(T, tup) end end +function _unsafe_load_tuple(::Type{NTuple{N,T}}, bytes::Vector{UInt8}, i::Integer) where {N,T} + x = Ref(bytes, i) + y = Ref{NTuple{N,T}}() + ArrowTypes._unsafe_cast!(y, x, N) + return y[] +end + @propagate_inbounds function Base.setindex!(l::FixedSizeList{T}, v::T, i::Integer) where {T} @boundscheck checkbounds(l, i) if v === missing diff --git a/src/arrowtypes.jl b/src/arrowtypes.jl index 76083ed8..b04a6130 100644 --- a/src/arrowtypes.jl +++ b/src/arrowtypes.jl @@ -73,19 +73,24 @@ ArrowType(::Type{UUID}) = FixedSizeListType() gettype(::Type{UUID}) = UInt8 getsize(::Type{UUID}) = 16 -function _unsafe_cast(::Type{B}, a::A)::B where {B,A} - a = Ref(a) - b = Ref{B}() - GC.@preserve a b begin - ptra = Base.unsafe_convert(Ptr{A}, a) - ptrb = Base.unsafe_convert(Ptr{B}, b) - unsafe_copyto!(Ptr{A}(ptrb), ptra, 1) +function _cast(::Type{Y}, x)::Y where {Y} + y = Ref{Y}() + _unsafe_cast!(y, Ref(x), 1) + return y[] +end + +function _unsafe_cast!(y::Ref{Y}, x::Ref, n::Integer) where {Y} + X = eltype(x) + GC.@preserve x y begin + ptr_x = Base.unsafe_convert(Ptr{X}, x) + ptr_y = Base.unsafe_convert(Ptr{Y}, y) + unsafe_copyto!(Ptr{X}(ptr_y), ptr_x, n) end - return b[] + return y end -arrowconvert(::Type{NTuple{16,UInt8}}, u::UUID) = _unsafe_cast(NTuple{16,UInt8}, u.value) -arrowconvert(::Type{UUID}, u::NTuple{16,UInt8}) = UUID(_unsafe_cast(UInt128, u)) +arrowconvert(::Type{NTuple{16,UInt8}}, u::UUID) = _cast(NTuple{16,UInt8}, u.value) +arrowconvert(::Type{UUID}, u::NTuple{16,UInt8}) = UUID(_cast(UInt128, u)) # These methods are included as deprecation paths to allow reading Arrow files that may have # been written before Arrow.jl's current UUID <-> NTuple{16,UInt8} mapping existed (in which case