nanoarrow 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ module Nanoarrow
2
+ class ArrayViewBaseIterator
3
+ def initialize(schema)
4
+ @schema = Utils.c_schema(schema)
5
+ @schema_view = Utils.c_schema_view(schema)
6
+ @array_view = CArrayView.from_schema(@schema)
7
+ end
8
+
9
+ def set_array(array)
10
+ @array_view.set_array(array)
11
+ end
12
+ end
13
+
14
+ class RbIterator < ArrayViewBaseIterator
15
+ def self.get_iterator(obj, schema = nil)
16
+ stream = Utils.c_array_stream(obj, schema)
17
+ iterator = new(stream.get_cached_schema)
18
+ Enumerator.new do |yielder|
19
+ while (array = stream.get_next)
20
+ iterator.set_array(array)
21
+ iterator.each(&yielder)
22
+ end
23
+ end
24
+ end
25
+
26
+ def initialize(schema)
27
+ super(schema)
28
+ end
29
+
30
+ def each(&block)
31
+ type_id = @schema_view.type_id
32
+ if !ITEMS_ITER_LOOKUP.include?(type_id)
33
+ raise KeyError, "Can't resolve iterator for type #{@schema_view.type.inspect}"
34
+ end
35
+
36
+ factory = method(ITEMS_ITER_LOOKUP.fetch(type_id))
37
+ factory.(&block)
38
+ end
39
+
40
+ private
41
+
42
+ def each_bool(&block)
43
+ @array_view.each_bool(&block)
44
+ end
45
+
46
+ def each_int(&block)
47
+ @array_view.each_int(&block)
48
+ end
49
+
50
+ def each_uint(&block)
51
+ @array_view.each_uint(&block)
52
+ end
53
+
54
+ def each_double(&block)
55
+ @array_view.each_double(&block)
56
+ end
57
+
58
+ def each_string(&block)
59
+ @array_view.each_string(&block)
60
+ end
61
+
62
+ def each_binary(&block)
63
+ @array_view.each_binary(&block)
64
+ end
65
+
66
+ def each_date(&block)
67
+ wrap = ->(v) { block.call(v.nil? ? v : EPOCH + v) }
68
+ @array_view.each_int(&wrap)
69
+ end
70
+
71
+ def each_timestamp(&block)
72
+ wrap =
73
+ case @schema_view.time_unit
74
+ when "s"
75
+ ->(v) { block.call(v.nil? ? v : Time.at(v)) }
76
+ when "ms"
77
+ ->(v) { block.call(v.nil? ? v : Time.at(v / 1_000, v % 1_000, :millisecond)) }
78
+ when "us"
79
+ ->(v) { block.call(v.nil? ? v : Time.at(v / 1_000_000, v % 1_000_000, :microsecond)) }
80
+ when "ns"
81
+ ->(v) { block.call(v.nil? ? v : Time.at(v / 1_000_000_000, v % 1_000_000_000, :nanosecond)) }
82
+ else
83
+ raise Todo
84
+ end
85
+ @array_view.each_int(&wrap)
86
+ end
87
+
88
+ ITEMS_ITER_LOOKUP = {
89
+ Type::BOOL => :each_bool,
90
+ Type::INT8 => :each_int,
91
+ Type::UINT8 => :each_uint,
92
+ Type::INT16 => :each_int,
93
+ Type::UINT16 => :each_uint,
94
+ Type::INT32 => :each_int,
95
+ Type::UINT32 => :each_uint,
96
+ Type::INT64 => :each_int,
97
+ Type::UINT64 => :each_uint,
98
+ Type::HALF_FLOAT => :each_double,
99
+ Type::FLOAT => :each_double,
100
+ Type::DOUBLE => :each_double,
101
+ Type::STRING => :each_string,
102
+ Type::LARGE_STRING => :each_string,
103
+ Type::STRING_VIEW => :each_string,
104
+ Type::BINARY => :each_binary,
105
+ Type::LARGE_BINARY => :each_binary,
106
+ Type::BINARY_VIEW => :each_binary,
107
+ Type::FIXED_SIZE_BINARY => :each_binary,
108
+ Type::DATE32 => :each_date,
109
+ Type::DATE64 => :each_date,
110
+ Type::TIMESTAMP => :each_timestamp,
111
+ }
112
+ end
113
+ end
@@ -0,0 +1,85 @@
1
+ module Nanoarrow
2
+ class Schema
3
+ def initialize(
4
+ obj,
5
+ name: nil,
6
+ nullable: nil,
7
+ metadata: nil,
8
+ fields: nil,
9
+ **params
10
+ )
11
+ if obj.is_a?(Integer)
12
+ @c_schema = Utils.c_schema_from_type_and_params(obj, params)
13
+ else
14
+ if params.any?
15
+ raise ArgumentError, "params are only supported for obj of class Type"
16
+ end
17
+ @c_schema = Utils.c_schema(obj)
18
+ end
19
+
20
+ if !name.nil? || !nullable.nil? || !metadata.nil? || !fields.nil?
21
+ @c_schema = @c_schema.modify(nil, name, nil, nullable, metadata, fields, nil, true)
22
+ end
23
+
24
+ @c_schema_view = CSchemaView.new(@c_schema)
25
+ end
26
+
27
+ def type
28
+ @c_schema_view.type
29
+ end
30
+
31
+ def name
32
+ @c_schema.name
33
+ end
34
+
35
+ def nullable
36
+ @c_schema_view.nullable
37
+ end
38
+
39
+ def metadata
40
+ @c_schema.metadata
41
+ end
42
+
43
+ def byte_width
44
+ if @c_schema_view.type_id == Type::FIXED_SIZE_BINARY
45
+ @c_schema_view.fixed_size
46
+ end
47
+ end
48
+
49
+ def unit
50
+ @c_schema_view.time_unit
51
+ end
52
+
53
+ def timezone
54
+ @c_schema_view.timezone
55
+ end
56
+
57
+ def precision
58
+ @c_schema_view.decimal_precision
59
+ end
60
+
61
+ def scale
62
+ @c_schema_view.decimal_scale
63
+ end
64
+
65
+ def n_fields
66
+ @c_schema.n_children
67
+ end
68
+
69
+ def field(i)
70
+ Schema.new(@c_schema.child(i).deep_dup)
71
+ end
72
+
73
+ def fields
74
+ n_fields.times.map { |i| field(i) }
75
+ end
76
+
77
+ def inspect
78
+ @c_schema.to_s
79
+ end
80
+
81
+ def arrow_c_schema
82
+ @c_schema.arrow_c_schema
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,157 @@
1
+ module Nanoarrow
2
+ def self.null(nullable: true)
3
+ Schema.new(Type::NULL, nullable:)
4
+ end
5
+
6
+ def self.bool(nullable: true)
7
+ Schema.new(Type::BOOL, nullable:)
8
+ end
9
+
10
+ def self.int8(nullable: true)
11
+ Schema.new(Type::INT8, nullable:)
12
+ end
13
+
14
+ def self.uint8(nullable: true)
15
+ Schema.new(Type::UINT8, nullable:)
16
+ end
17
+
18
+ def self.int16(nullable: true)
19
+ Schema.new(Type::INT16, nullable:)
20
+ end
21
+
22
+ def self.uint16(nullable: true)
23
+ Schema.new(Type::UINT16, nullable:)
24
+ end
25
+
26
+ def self.int32(nullable: true)
27
+ Schema.new(Type::INT32, nullable:)
28
+ end
29
+
30
+ def self.uint32(nullable: true)
31
+ Schema.new(Type::UINT32, nullable:)
32
+ end
33
+
34
+ def self.int64(nullable: true)
35
+ Schema.new(Type::INT64, nullable:)
36
+ end
37
+
38
+ def self.uint64(nullable: true)
39
+ Schema.new(Type::UINT64, nullable:)
40
+ end
41
+
42
+ def self.half_float(nullable: true)
43
+ Schema.new(Type::HALF_FLOAT, nullable:)
44
+ end
45
+
46
+ def self.float(nullable: true)
47
+ Schema.new(Type::FLOAT, nullable:)
48
+ end
49
+
50
+ def self.double(nullable: true)
51
+ Schema.new(Type::DOUBLE, nullable:)
52
+ end
53
+
54
+ def self.string(nullable: true)
55
+ Schema.new(Type::STRING, nullable:)
56
+ end
57
+
58
+ def self.large_string(nullable: true)
59
+ Schema.new(Type::LARGE_STRING, nullable:)
60
+ end
61
+
62
+ def self.string_view(nullable: true)
63
+ Schema.new(Type::STRING_VIEW, nullable:)
64
+ end
65
+
66
+ def self.binary(nullable: true)
67
+ Schema.new(Type::BINARY, nullable:)
68
+ end
69
+
70
+ def self.large_binary(nullable: true)
71
+ Schema.new(Type::LARGE_BINARY, nullable:)
72
+ end
73
+
74
+ def self.binary_view(nullable: true)
75
+ Schema.new(Type::BINARY_VIEW, nullable:)
76
+ end
77
+
78
+ def self.fixed_size_binary(byte_width, nullable: true)
79
+ Schema.new(Type::FIXED_SIZE_BINARY, byte_width:, nullable:)
80
+ end
81
+
82
+ def self.date32(nullable: true)
83
+ Schema.new(Type::DATE32, nullable:)
84
+ end
85
+
86
+ def self.date64(nullable: true)
87
+ Schema.new(Type::DATE64, nullable:)
88
+ end
89
+
90
+ def self.time32(unit, nullable: true)
91
+ Schema.new(Type::TIME32, unit:, nullable:)
92
+ end
93
+
94
+ def self.time64(unit, nullable: true)
95
+ Schema.new(Type::TIME64, unit:, nullable:)
96
+ end
97
+
98
+ def self.timestamp(unit, timezone: nil, nullable: true)
99
+ Schema.new(Type::TIMESTAMP, unit:, timezone:, nullable:)
100
+ end
101
+
102
+ def self.duration(unit, nullable: true)
103
+ Schema.new(Type::DURATION, unit:, nullable:)
104
+ end
105
+
106
+ def self.interval_months(nullable: true)
107
+ Schema.new(Type::INTERVAL_MONTHS, nullable:)
108
+ end
109
+
110
+ def self.interval_day_time(nullable: true)
111
+ Schema.new(Type::INTERVAL_DAY_TIME, nullable:)
112
+ end
113
+
114
+ def self.interval_month_day_nano(nullable: true)
115
+ Schema.new(Type::INTERVAL_MONTH_DAY_NANO, nullable:)
116
+ end
117
+
118
+ def self.decimal128(precision, scale, nullable: true)
119
+ Schema.new(Type::DECIMAL128, precision:, scale:, nullable:)
120
+ end
121
+
122
+ def self.decimal256(precision, scale, nullable: true)
123
+ Schema.new(Type::DECIMAL256, precision:, scale:, nullable:)
124
+ end
125
+
126
+ def self.struct(fields, nullable: true)
127
+ Schema.new(Type::STRUCT, fields:, nullable:)
128
+ end
129
+
130
+ def self.list(value_type, nullable: true)
131
+ Schema.new(Type::LIST, value_type:, nullable:)
132
+ end
133
+
134
+ def self.large_list(value_type, nullable: true)
135
+ Schema.new(Type::LARGE_LIST, value_type:, nullable:)
136
+ end
137
+
138
+ def self.fixed_size_list(value_type, list_size, nullable: true)
139
+ Schema.new(Type::FIXED_SIZE_LIST, value_type:, list_size:, nullable:)
140
+ end
141
+
142
+ def self.map(key_type, value_type, keys_sorted: false, nullable: true)
143
+ Schema.new(Type::MAP, key_type:, value_type:, keys_sorted:, nullable:)
144
+ end
145
+
146
+ def self.dictionary(index_type, value_type, dictionary_ordered: false)
147
+ Schema.new(Type::DICTIONARY, index_type:, value_type:, dictionary_ordered:)
148
+ end
149
+
150
+ def self.sparse_union(fields, nullable: true)
151
+ Schema.new(Type::SPARSE_UNION, fields:, nullable:)
152
+ end
153
+
154
+ def self.dense_union(fields, nullable: true)
155
+ Schema.new(Type::DENSE_UNION, fields:, nullable:)
156
+ end
157
+ end
@@ -0,0 +1,127 @@
1
+ module Nanoarrow
2
+ module Utils
3
+ def self.c_array(obj, schema)
4
+ if !schema.nil?
5
+ schema = c_schema(schema)
6
+ end
7
+
8
+ if obj.is_a?(CArray) && schema.nil?
9
+ return obj
10
+ end
11
+
12
+ if obj.respond_to?(:arrow_c_array)
13
+ raise Todo if schema
14
+ return CArray.import_from_c_capsule(obj.arrow_c_array)
15
+ end
16
+
17
+ if obj.is_a?(Capsule) && obj.name == "arrow_array"
18
+ raise Todo if schema
19
+ return CArray.import_from_c_capsule(obj)
20
+ end
21
+
22
+ if schema.nil?
23
+ raise Todo
24
+ end
25
+ builder = ArrayFromIterableBuilder.new(schema)
26
+ builder.build_c_array(obj)
27
+ end
28
+
29
+ def self.c_array_stream(obj, schema)
30
+ if !schema.nil?
31
+ schema = c_schema(schema)
32
+ end
33
+
34
+ if obj.is_a?(CArrayStream) && schema.nil?
35
+ return obj
36
+ end
37
+
38
+ if obj.respond_to?(:arrow_c_stream)
39
+ raise Todo if schema
40
+ return CArrayStream.import_from_c_capsule(obj.arrow_c_stream)
41
+ end
42
+
43
+ if obj.is_a?(Capsule) && obj.name == "arrow_array_stream"
44
+ raise Todo if schema
45
+ return CArrayStream.import_from_c_capsule(obj)
46
+ end
47
+
48
+ array = c_array(obj, schema)
49
+ CArrayStream.from_c_arrays([array], array.schema, false)
50
+ end
51
+
52
+ def self.c_schema(obj)
53
+ if obj.is_a?(CSchema)
54
+ return obj
55
+ end
56
+
57
+ if obj.respond_to?(:arrow_c_schema)
58
+ return CSchema.import_from_c_capsule(obj.arrow_c_schema)
59
+ end
60
+
61
+ if obj.is_a?(Capsule) && obj.name == "arrow_schema"
62
+ return CSchema.import_from_c_capsule(obj)
63
+ end
64
+
65
+ raise TypeError, "Can't convert object of type #{obj.class.name} to CSchema"
66
+ end
67
+
68
+ def self.c_schema_view(obj)
69
+ if obj.is_a?(CSchemaView)
70
+ return obj
71
+ end
72
+
73
+ CSchemaView.new(c_schema(obj))
74
+ end
75
+
76
+ def self.c_schema_from_type_and_params(type, params)
77
+ factory = CSchemaBuilder.new
78
+
79
+ if [Type::DECIMAL128, Type::DECIMAL256].include?(type)
80
+ precision = Integer(params.delete(:precision))
81
+ scale = Integer(params.delete(:scale))
82
+ factory.set_type_decimal(type, precision, scale)
83
+
84
+ elsif [Type::TIME32, Type::TIME64, Type::TIMESTAMP, Type::DURATION].include?(type)
85
+ time_unit = params.delete(:unit)
86
+ timezone = params.delete(:timezone)
87
+ factory.set_type_date_time(type, TIME_UNITS.fetch(time_unit), timezone)
88
+
89
+ elsif type == Type::FIXED_SIZE_BINARY
90
+ factory.set_type_fixed_size(type, Integer(params.delete(:byte_width)))
91
+
92
+ elsif type == Type::LIST
93
+ raise Todo
94
+
95
+ elsif type == Type::LARGE_LIST
96
+ raise Todo
97
+
98
+ elsif type == Type::FIXED_SIZE_LIST
99
+ raise Todo
100
+
101
+ elsif type == Type::MAP
102
+ raise Todo
103
+
104
+ elsif type == Type::DICTIONARY
105
+ raise Todo
106
+
107
+ elsif type == Type::SPARSE_UNION
108
+ raise Todo
109
+
110
+ elsif type == Type::DENSE_UNION
111
+ raise Todo
112
+
113
+ else
114
+ factory.set_type(type)
115
+ end
116
+
117
+ if params.any?
118
+ unused = params.keys.map(&:inspect).join(", ")
119
+ raise ArgumentError, "Unused parameters whilst constructing Schema: #{unused}"
120
+ end
121
+
122
+ factory.set_name("")
123
+
124
+ factory.finish
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,3 @@
1
+ module Nanoarrow
2
+ VERSION = "0.1.0"
3
+ end
data/lib/nanoarrow.rb ADDED
@@ -0,0 +1,28 @@
1
+ # ext
2
+ require "nanoarrow/ext"
3
+
4
+ # stdlib
5
+ require "date"
6
+
7
+ # modules
8
+ require_relative "nanoarrow/array"
9
+ require_relative "nanoarrow/array_builder"
10
+ require_relative "nanoarrow/array_stream"
11
+ require_relative "nanoarrow/iterator"
12
+ require_relative "nanoarrow/schema"
13
+ require_relative "nanoarrow/types"
14
+ require_relative "nanoarrow/utils"
15
+ require_relative "nanoarrow/version"
16
+
17
+ module Nanoarrow
18
+ class Error < StandardError; end
19
+
20
+ class Todo < Error
21
+ def initialize(message = "not implemented yet")
22
+ super(message)
23
+ end
24
+ end
25
+
26
+ EPOCH = Date.new(1970, 1, 1)
27
+ TIME_UNITS = {"s" => 0, "ms" => 1, "us" => 2, "ns" => 3}
28
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nanoarrow
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Kane
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ email: andrew@ankane.org
13
+ executables: []
14
+ extensions:
15
+ - ext/nanoarrow/extconf.rb
16
+ extra_rdoc_files: []
17
+ files:
18
+ - CHANGELOG.md
19
+ - LICENSE.txt
20
+ - NOTICE.txt
21
+ - README.md
22
+ - ext/nanoarrow/array.c
23
+ - ext/nanoarrow/array_builder.c
24
+ - ext/nanoarrow/array_stream.c
25
+ - ext/nanoarrow/array_view.c
26
+ - ext/nanoarrow/buffer.c
27
+ - ext/nanoarrow/capsule.c
28
+ - ext/nanoarrow/ext.c
29
+ - ext/nanoarrow/ext.h
30
+ - ext/nanoarrow/extconf.rb
31
+ - ext/nanoarrow/mat_array_stream.c
32
+ - ext/nanoarrow/nanoarrow.c
33
+ - ext/nanoarrow/nanoarrow/nanoarrow.h
34
+ - ext/nanoarrow/rc.c
35
+ - ext/nanoarrow/schema.c
36
+ - ext/nanoarrow/schema_builder.c
37
+ - ext/nanoarrow/schema_view.c
38
+ - ext/nanoarrow/types.c
39
+ - ext/nanoarrow/utils.c
40
+ - lib/nanoarrow.rb
41
+ - lib/nanoarrow/array.rb
42
+ - lib/nanoarrow/array_builder.rb
43
+ - lib/nanoarrow/array_stream.rb
44
+ - lib/nanoarrow/iterator.rb
45
+ - lib/nanoarrow/schema.rb
46
+ - lib/nanoarrow/types.rb
47
+ - lib/nanoarrow/utils.rb
48
+ - lib/nanoarrow/version.rb
49
+ homepage: https://github.com/ankane/nanoarrow-ruby
50
+ licenses:
51
+ - Apache-2.0
52
+ metadata: {}
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.3'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubygems_version: 4.0.14
68
+ specification_version: 4
69
+ summary: Zero-dependency Arrow library for Ruby
70
+ test_files: []