maxmind-db-rust 0.1.4-x86_64-linux

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e09c312b29ebe97522fcd0ac7bfb3d2f8839ae21e441eaa307172c8dac0e9d6a
4
+ data.tar.gz: 74a5bdc6ae7da6f09784cb05c36a46f4f6cf5a01d60c7fdb8ee3035b2168567b
5
+ SHA512:
6
+ metadata.gz: 36fb733556e32833ce2afe1bad3a503c7094439f5ab0b08f8b4163e5a286c0ab3d18fefa4481758718c6307378cd5123453674c1d9741a40ed85b15d335823db
7
+ data.tar.gz: 0ba0534b27d5a74ec28f2e178564be1a93d79f82dd88eaab3a2658bd5a8f9cf04eb02b0ae5df843aa54f3c7d751a9dc08805b53c7a85abb56a35613de8040ce4
data/CHANGELOG.md ADDED
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.4] - 2025-11-16
11
+
12
+ ### Fixed
13
+
14
+ - Release workflow for publishing multiple platform-specific gems
15
+
16
+ ## [0.1.3] - 2025-11-16
17
+
18
+ ### Added
19
+
20
+ - Pre-compiled native gems for multiple platforms, eliminating the need to compile Rust during installation:
21
+ - `x86_64-linux` (Linux x86_64)
22
+ - `aarch64-linux` (Linux ARM64)
23
+ - `x86_64-darwin` (macOS Intel)
24
+ - `arm64-darwin` (macOS Apple Silicon)
25
+ - `x64-mingw-ucrt` (Windows)
26
+ - `x86_64-linux-musl` (Alpine Linux)
27
+ - Source gem as fallback for platforms without pre-compiled binaries
28
+
29
+ ## [0.1.2] - 2025-11-15
30
+
31
+ ### Added
32
+
33
+ - Automated release script (`dev-bin/release.sh`) that validates changelog dates, updates gemspec version, runs tests, and creates GitHub releases
34
+
35
+ ### Changed
36
+
37
+ - Updated actions/checkout from v4 to v5 in GitHub workflows
38
+
39
+ ### Fixed
40
+
41
+ - Release workflow no longer runs twice (removed redundant triggers)
42
+
43
+ ### Removed
44
+
45
+ - Unused test/maxmind-db-reader-ruby git submodule (documentation now references upstream repository by URL)
46
+
47
+ ## [0.1.1] - 2025-11-15
48
+
49
+ ### Fixed
50
+
51
+ - Release workflow now has environment set.
52
+
53
+ ## [0.1.0] - 2025-11-15
54
+
55
+ ### Added
56
+
57
+ - Initial release
58
+ - Reader class with `get()`, `get_with_prefix_length()`, `metadata()`, `close()`, and `closed()` methods
59
+ - Metadata class with all standard MaxMind DB metadata attributes
60
+ - Support for MODE_AUTO, MODE_MEMORY, and MODE_MMAP modes
61
+ - Iterator support via `each` method (Enumerable interface)
62
+ - Iterate over all networks in database
63
+ - Network-scoped iteration with optional CIDR parameter (String or IPAddr)
64
+ - InvalidDatabaseError exception for corrupt databases
65
+ - Thread-safe implementation using Rust Arc and RwLock
66
+ - Support for both String and IPAddr IP address inputs
67
+ - High-performance Rust implementation using maxminddb crate
68
+ - Comprehensive API documentation
69
+
70
+ ### Not Implemented
71
+
72
+ - MODE_FILE support (use MODE_MMAP instead)
73
+ - File descriptor support in constructor
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,509 @@
1
+ # Contributing to maxmind-db-rust
2
+
3
+ Thank you for your interest in contributing to maxmind-db-rust! This document provides guidelines and instructions for developers.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Development Setup](#development-setup)
8
+ - [Building the Extension](#building-the-extension)
9
+ - [Running Tests](#running-tests)
10
+ - [Code Quality](#code-quality)
11
+ - [Project Structure](#project-structure)
12
+ - [Making Changes](#making-changes)
13
+ - [Testing Guidelines](#testing-guidelines)
14
+ - [Submitting Changes](#submitting-changes)
15
+ - [Release Process](#release-process)
16
+
17
+ ## Development Setup
18
+
19
+ ### Prerequisites
20
+
21
+ - Ruby 3.2 or higher
22
+ - Rust toolchain (stable)
23
+ - Bundler
24
+ - Git
25
+
26
+ ### Installing Rust
27
+
28
+ If you don't have Rust installed:
29
+
30
+ ```bash
31
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
32
+ source $HOME/.cargo/env
33
+ ```
34
+
35
+ ### Clone and Setup
36
+
37
+ ```bash
38
+ git clone https://github.com/oschwald/maxmind-db-rust-ruby.git
39
+ cd maxmind-db-rust-ruby
40
+
41
+ # Initialize git submodules (for test data)
42
+ git submodule update --init --recursive
43
+
44
+ # Install dependencies
45
+ bundle install
46
+
47
+ # Configure git to use the .githooks directory
48
+ git config core.hooksPath .githooks
49
+ ```
50
+
51
+ This will enable the pre-commit hook that runs `precious lint` on staged files before each commit.
52
+
53
+ ## Building the Extension
54
+
55
+ ### First Time Build
56
+
57
+ ```bash
58
+ # Compile the Rust extension
59
+ bundle exec rake compile
60
+ ```
61
+
62
+ This will:
63
+
64
+ 1. Run `extconf.rb` to generate the Makefile
65
+ 2. Compile the Rust code using rb-sys
66
+ 3. Place the compiled extension in `lib/maxmind/db/`
67
+
68
+ ### Clean Build
69
+
70
+ ```bash
71
+ # Clean build artifacts
72
+ bundle exec rake clean
73
+
74
+ # Clean and rebuild
75
+ bundle exec rake clobber compile
76
+ ```
77
+
78
+ ### Development Build (Debug)
79
+
80
+ The default rake task builds in release mode. For faster compile times during development:
81
+
82
+ ```bash
83
+ # Set environment variable for debug builds
84
+ CARGO_PROFILE=dev bundle exec rake compile
85
+ ```
86
+
87
+ Note: Debug builds are significantly slower at runtime but compile faster.
88
+
89
+ ## Running Tests
90
+
91
+ ### Test Organization
92
+
93
+ Tests are organized into two categories:
94
+
95
+ 1. **Our Own Tests** (`test/*_test.rb`)
96
+ - Tests specific to this implementation
97
+ - License: ISC (same as project)
98
+
99
+ 2. **MaxMind Upstream Tests** (`test/maxmind/test_*.rb`)
100
+ - Adapted from official MaxMind-DB-Reader-ruby
101
+ - License: Apache-2.0 or MIT (MaxMind, Inc.)
102
+ - See `test/maxmind/README.md` for details
103
+
104
+ ### Running Tests
105
+
106
+ ```bash
107
+ # Run all tests (recommended before submitting PR)
108
+ bundle exec rake test
109
+
110
+ # Run only our own tests
111
+ bundle exec rake test_own
112
+
113
+ # Run only MaxMind upstream compatibility tests
114
+ bundle exec rake test_maxmind
115
+
116
+ # Run with verbose output
117
+ bundle exec rake test_verbose
118
+
119
+ # Run specific test file
120
+ bundle exec ruby test/reader_test.rb
121
+
122
+ # Run specific test method
123
+ bundle exec ruby test/reader_test.rb -n test_get_ipv4_address
124
+ ```
125
+
126
+ ### Test Data
127
+
128
+ Test databases are stored in `test/data/MaxMind-DB/` as a git submodule. If tests are failing with "file not found" errors:
129
+
130
+ ```bash
131
+ git submodule update --init --recursive
132
+ ```
133
+
134
+ ## Code Quality
135
+
136
+ ### Precious (Recommended)
137
+
138
+ The easiest way to run all linters and formatters is using [precious](https://github.com/houseabsolute/precious):
139
+
140
+ ```bash
141
+ # Install precious (once)
142
+ cargo install precious
143
+
144
+ # Check all linters
145
+ precious lint --all
146
+
147
+ # Auto-fix all issues
148
+ precious tidy --all
149
+
150
+ # Check only staged files (useful before committing)
151
+ precious lint --staged
152
+
153
+ # Run specific linter
154
+ precious lint -c rubocop
155
+ ```
156
+
157
+ The pre-commit hook automatically runs `precious lint --staged` before each commit.
158
+
159
+ ### RuboCop (Ruby)
160
+
161
+ ```bash
162
+ # Check Ruby code style
163
+ bundle exec rubocop
164
+
165
+ # Auto-fix issues
166
+ bundle exec rubocop -a
167
+
168
+ # Check specific files
169
+ bundle exec rubocop lib/maxmind/db/rust.rb
170
+ ```
171
+
172
+ ### Clippy (Rust)
173
+
174
+ ```bash
175
+ # Run Rust linter
176
+ cd ext/maxmind_db_rust
177
+ cargo clippy -- -D warnings
178
+ ```
179
+
180
+ ### Formatting
181
+
182
+ ```bash
183
+ # Format Rust code
184
+ cd ext/maxmind_db_rust
185
+ cargo fmt
186
+
187
+ # Check formatting without changing files
188
+ cargo fmt -- --check
189
+ ```
190
+
191
+ ## Project Structure
192
+
193
+ ```
194
+ maxmind-db-rust-ruby/
195
+ ├── ext/maxmind_db_rust/ # Rust extension code
196
+ │ ├── Cargo.toml # Rust dependencies
197
+ │ ├── extconf.rb # Ruby build configuration
198
+ │ └── src/
199
+ │ └── lib.rs # Main Rust implementation
200
+ ├── lib/ # Ruby integration layer
201
+ │ └── maxmind/
202
+ │ └── db/
203
+ │ └── rust.rb # Ruby API wrapper
204
+ ├── test/ # Test suite
205
+ │ ├── *_test.rb # Our own tests
206
+ │ ├── maxmind/ # Upstream tests (MaxMind copyright)
207
+ │ │ ├── README.md # Licensing info
208
+ │ │ └── test_*.rb # Adapted tests
209
+ │ └── data/
210
+ │ └── MaxMind-DB/ # Test databases (submodule)
211
+ ├── Rakefile # Build and test tasks
212
+ ├── maxmind-db-rust.gemspec # Gem specification
213
+ ├── README.md # User documentation
214
+ ├── CONTRIBUTING.md # This file
215
+ ├── CHANGELOG.md # Version history
216
+ └── LICENSE # ISC License
217
+ ```
218
+
219
+ ## Making Changes
220
+
221
+ ### Workflow
222
+
223
+ 1. **Create a branch** for your changes:
224
+
225
+ ```bash
226
+ git checkout -b feature/my-new-feature
227
+ ```
228
+
229
+ 2. **Make your changes**:
230
+ - Rust code: `ext/maxmind_db_rust/src/lib.rs`
231
+ - Ruby wrapper: `lib/maxmind/db/rust.rb`
232
+ - Tests: Add tests in `test/` directory
233
+
234
+ 3. **Compile and test**:
235
+
236
+ ```bash
237
+ bundle exec rake compile
238
+ bundle exec rake test
239
+ ```
240
+
241
+ 4. **Check code quality**:
242
+
243
+ ```bash
244
+ bundle exec rubocop
245
+ cd ext/maxmind_db_rust && cargo clippy && cargo fmt
246
+ ```
247
+
248
+ 5. **Commit your changes**:
249
+ ```bash
250
+ git add .
251
+ git commit -m "Add feature: description"
252
+ ```
253
+
254
+ ### Commit Message Guidelines
255
+
256
+ - Use present tense ("Add feature" not "Added feature")
257
+ - Use imperative mood ("Move cursor to..." not "Moves cursor to...")
258
+ - First line should be 50 characters or less
259
+ - Reference issues and pull requests when relevant
260
+
261
+ Example:
262
+
263
+ ```
264
+ Add support for custom metadata attributes
265
+
266
+ - Implement metadata attribute getter
267
+ - Add tests for custom attributes
268
+ - Update documentation
269
+
270
+ Fixes #123
271
+ ```
272
+
273
+ ## Testing Guidelines
274
+
275
+ ### Writing Tests
276
+
277
+ When adding new features or fixing bugs:
278
+
279
+ 1. **Add tests to our own test suite** (`test/*_test.rb`):
280
+
281
+ ```ruby
282
+ def test_new_feature
283
+ reader = MaxMind::DB::Rust::Reader.new('path/to/test.mmdb')
284
+ result = reader.new_method
285
+ assert_equal expected_value, result
286
+ reader.close
287
+ end
288
+ ```
289
+
290
+ 2. **Ensure existing tests pass**:
291
+
292
+ ```bash
293
+ bundle exec rake test
294
+ ```
295
+
296
+ 3. **Test both modes** (MMAP and MEMORY) when relevant:
297
+ ```ruby
298
+ [MaxMind::DB::Rust::MODE_MMAP, MaxMind::DB::Rust::MODE_MEMORY].each do |mode|
299
+ reader = MaxMind::DB::Rust::Reader.new(path, mode: mode)
300
+ # Test logic here
301
+ reader.close
302
+ end
303
+ ```
304
+
305
+ ### Test Coverage
306
+
307
+ - Test normal operation (happy path)
308
+ - Test edge cases (empty results, boundary conditions)
309
+ - Test error conditions (invalid input, closed readers, etc.)
310
+ - Test thread safety for concurrent operations
311
+ - Test both IPv4 and IPv6 addresses
312
+
313
+ ### Upstream Test Synchronization
314
+
315
+ When the official MaxMind-DB-Reader-ruby gem is updated:
316
+
317
+ 1. Clone or update a local copy of the upstream repository:
318
+
319
+ ```bash
320
+ # Clone to a temporary location
321
+ git clone https://github.com/maxmind/MaxMind-DB-Reader-ruby.git /tmp/maxmind-db-reader-ruby
322
+ cd /tmp/maxmind-db-reader-ruby
323
+
324
+ # Or update existing clone
325
+ git pull origin main
326
+ ```
327
+
328
+ 2. Review changes:
329
+
330
+ ```bash
331
+ cd /tmp/maxmind-db-reader-ruby
332
+ git log --oneline --since="3 months ago" -- test/
333
+ git diff HEAD~10..HEAD -- test/test_reader.rb
334
+ ```
335
+
336
+ 3. Apply relevant changes to `test/maxmind/test_reader.rb`:
337
+ - Maintain our namespace changes (MaxMind::DB::Rust)
338
+ - Keep MODE_MMAP instead of MODE_FILE
339
+ - Preserve our path adjustments
340
+ - Update expected error messages if needed
341
+
342
+ 4. Document changes in `test/maxmind/README.md`
343
+
344
+ ## Submitting Changes
345
+
346
+ ### Before Submitting a Pull Request
347
+
348
+ 1. **Ensure all tests pass**:
349
+
350
+ ```bash
351
+ bundle exec rake test
352
+ ```
353
+
354
+ 2. **Run code quality checks**:
355
+
356
+ ```bash
357
+ bundle exec rubocop
358
+ cd ext/maxmind_db_rust && cargo clippy && cargo fmt --check
359
+ ```
360
+
361
+ 3. **Update documentation** if needed:
362
+ - README.md for user-facing changes
363
+ - CHANGELOG.md for notable changes
364
+ - Code comments for complex logic
365
+
366
+ 4. **Rebase on main**:
367
+ ```bash
368
+ git fetch origin
369
+ git rebase origin/main
370
+ ```
371
+
372
+ ### Pull Request Process
373
+
374
+ 1. **Push your branch**:
375
+
376
+ ```bash
377
+ git push origin feature/my-new-feature
378
+ ```
379
+
380
+ 2. **Create a pull request** on GitHub with:
381
+ - Clear description of changes
382
+ - Reference to related issues
383
+ - Screenshots/examples if applicable
384
+ - Test results
385
+
386
+ 3. **Address review feedback**:
387
+ - Make requested changes
388
+ - Push updates to the same branch
389
+ - Respond to comments
390
+
391
+ 4. **Wait for approval** and merge
392
+
393
+ ## Release Process
394
+
395
+ ### Version Numbering
396
+
397
+ We follow [Semantic Versioning](https://semver.org/):
398
+
399
+ - **MAJOR**: Incompatible API changes
400
+ - **MINOR**: Backward-compatible functionality additions
401
+ - **PATCH**: Backward-compatible bug fixes
402
+
403
+ ### Creating a Release
404
+
405
+ 1. **Update version** in `maxmind-db-rust.gemspec`:
406
+
407
+ ```ruby
408
+ s.version = '0.2.0'
409
+ ```
410
+
411
+ 2. **Update CHANGELOG.md**:
412
+
413
+ ```markdown
414
+ ## [0.2.0] - 2025-01-15
415
+
416
+ ### Added
417
+
418
+ - New feature X
419
+
420
+ ### Fixed
421
+
422
+ - Bug fix Y
423
+ ```
424
+
425
+ 3. **Commit version bump**:
426
+
427
+ ```bash
428
+ git add maxmind-db-rust.gemspec CHANGELOG.md
429
+ git commit -m "Bump version to 0.2.0"
430
+ ```
431
+
432
+ 4. **Create and push tag**:
433
+
434
+ ```bash
435
+ git tag -a v0.2.0 -m "Release version 0.2.0"
436
+ git push origin main
437
+ git push origin v0.2.0
438
+ ```
439
+
440
+ 5. **Create GitHub Release**:
441
+
442
+ Go to https://github.com/oschwald/maxmind-db-rust-ruby/releases/new and create a new release with tag `v0.2.0`.
443
+
444
+ The GitHub Actions workflow will automatically:
445
+ - Build native gems for all supported platforms:
446
+ - `x86_64-linux` (Linux x86_64)
447
+ - `aarch64-linux` (Linux ARM64)
448
+ - `x86_64-darwin` (macOS Intel)
449
+ - `arm64-darwin` (macOS Apple Silicon)
450
+ - `x64-mingw-ucrt` (Windows)
451
+ - `x86_64-linux-musl` (Alpine Linux)
452
+ - Build a source gem (fallback for unsupported platforms)
453
+ - Push all gems to RubyGems.org
454
+
455
+ ### Building Native Gems
456
+
457
+ Native gems for multiple platforms are built automatically by the CI/CD pipeline using the `oxidize-rb/actions/cross-gem` GitHub Action. The workflow handles cross-compilation for all supported platforms without requiring local Docker setup.
458
+
459
+ ## Performance Considerations
460
+
461
+ ### Benchmarking
462
+
463
+ When making performance-related changes:
464
+
465
+ 1. **Create benchmark script**:
466
+
467
+ ```ruby
468
+ require 'benchmark'
469
+ require 'maxmind/db/rust'
470
+
471
+ reader = MaxMind::DB::Rust::Reader.new('path/to/db.mmdb')
472
+ ips = File.readlines('test_ips.txt').map(&:strip)
473
+
474
+ Benchmark.bm do |x|
475
+ x.report("lookups:") do
476
+ 100_000.times { reader.get(ips.sample) }
477
+ end
478
+ end
479
+ ```
480
+
481
+ 2. **Compare before and after** your changes
482
+
483
+ 3. **Document results** in PR description
484
+
485
+ ### Optimization Tips
486
+
487
+ - Use MODE_MMAP for best performance (default)
488
+ - Release GIL during I/O operations (already implemented)
489
+ - Minimize Ruby object allocations in hot paths
490
+ - Use Arc for thread-safe sharing instead of cloning
491
+
492
+ ## Getting Help
493
+
494
+ - **Issues**: https://github.com/oschwald/maxmind-db-rust-ruby/issues
495
+ - **Discussions**: Use GitHub Discussions for questions
496
+ - **MaxMind Docs**: https://maxmind.github.io/MaxMind-DB/
497
+
498
+ ## Code of Conduct
499
+
500
+ - Be respectful and inclusive
501
+ - Provide constructive feedback
502
+ - Focus on the code, not the person
503
+ - Help others learn and grow
504
+
505
+ ## License
506
+
507
+ By contributing, you agree that your contributions will be licensed under the ISC License.
508
+
509
+ Thank you for contributing! 🎉
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025, Gregory Oschwald
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,343 @@
1
+ # maxmind-db-rust
2
+
3
+ [![Test](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/test.yml/badge.svg)](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/test.yml)
4
+ [![Lint](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/lint.yml/badge.svg)](https://github.com/oschwald/maxmind-db-rust-ruby/actions/workflows/lint.yml)
5
+
6
+ A high-performance Rust-based Ruby gem for reading MaxMind DB files. Provides API compatibility with the official `maxmind-db` gem while leveraging Rust for superior performance.
7
+
8
+ > **Note:** This is an unofficial library and is not endorsed by MaxMind. For the official Ruby library, see [maxmind-db](https://github.com/maxmind/MaxMind-DB-Reader-ruby).
9
+
10
+ ## Features
11
+
12
+ - **High Performance**: Rust-based implementation provides significantly faster lookups than pure Ruby
13
+ - **API Compatible**: Familiar API similar to the official MaxMind::DB gem
14
+ - **Thread-Safe**: Safe to use from multiple threads
15
+ - **Memory Modes**: Support for both memory-mapped (MMAP) and in-memory modes
16
+ - **Iterator Support**: Iterate over all networks in the database (extension feature)
17
+ - **Type Support**: Works with both String and IPAddr objects
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'maxmind-db-rust'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```bash
36
+ gem install maxmind-db-rust
37
+ ```
38
+
39
+ ## Requirements
40
+
41
+ - Ruby 3.2 or higher
42
+ - Rust toolchain (for building from source)
43
+
44
+ ## Usage
45
+
46
+ ### Basic Usage
47
+
48
+ ```ruby
49
+ require 'maxmind/db/rust'
50
+
51
+ # Open database
52
+ reader = MaxMind::DB::Rust::Reader.new(
53
+ 'GeoIP2-City.mmdb',
54
+ mode: MaxMind::DB::Rust::MODE_MEMORY
55
+ )
56
+
57
+ # Lookup an IP address
58
+ record = reader.get('8.8.8.8')
59
+ if record
60
+ puts record['country']['iso_code']
61
+ puts record['country']['names']['en']
62
+ puts record['city']['names']['en']
63
+ end
64
+
65
+ # Close the database
66
+ reader.close
67
+ ```
68
+
69
+ ### Get with Prefix Length
70
+
71
+ ```ruby
72
+ require 'maxmind/db/rust'
73
+
74
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
75
+
76
+ record, prefix_length = reader.get_with_prefix_length('8.8.8.8')
77
+ puts "Record: #{record}"
78
+ puts "Prefix length: #{prefix_length}"
79
+
80
+ reader.close
81
+ ```
82
+
83
+ ### Using IPAddr Objects
84
+
85
+ ```ruby
86
+ require 'maxmind/db/rust'
87
+ require 'ipaddr'
88
+
89
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
90
+
91
+ ip = IPAddr.new('8.8.8.8')
92
+ record = reader.get(ip)
93
+
94
+ reader.close
95
+ ```
96
+
97
+ ### Database Modes
98
+
99
+ ```ruby
100
+ require 'maxmind/db/rust'
101
+
102
+ # MODE_AUTO: Uses memory-mapped files (default, best performance)
103
+ reader = MaxMind::DB::Rust::Reader.new(
104
+ 'GeoIP2-City.mmdb',
105
+ mode: MaxMind::DB::Rust::MODE_AUTO
106
+ )
107
+
108
+ # MODE_MMAP: Explicitly use memory-mapped files (recommended)
109
+ reader = MaxMind::DB::Rust::Reader.new(
110
+ 'GeoIP2-City.mmdb',
111
+ mode: MaxMind::DB::Rust::MODE_MMAP
112
+ )
113
+
114
+ # MODE_MEMORY: Load entire database into memory
115
+ reader = MaxMind::DB::Rust::Reader.new(
116
+ 'GeoIP2-City.mmdb',
117
+ mode: MaxMind::DB::Rust::MODE_MEMORY
118
+ )
119
+ ```
120
+
121
+ ### Accessing Metadata
122
+
123
+ ```ruby
124
+ require 'maxmind/db/rust'
125
+
126
+ reader = MaxMind::DB::Rust::Reader.new('GeoIP2-City.mmdb')
127
+
128
+ metadata = reader.metadata
129
+ puts "Database type: #{metadata.database_type}"
130
+ puts "Node count: #{metadata.node_count}"
131
+ puts "Record size: #{metadata.record_size}"
132
+ puts "IP version: #{metadata.ip_version}"
133
+ puts "Build epoch: #{metadata.build_epoch}"
134
+ puts "Languages: #{metadata.languages.join(', ')}"
135
+ puts "Description: #{metadata.description}"
136
+
137
+ reader.close
138
+ ```
139
+
140
+ ### Iterator Support (Extension Feature)
141
+
142
+ Iterate over all networks in the database:
143
+
144
+ ```ruby
145
+ require 'maxmind/db/rust'
146
+
147
+ reader = MaxMind::DB::Rust::Reader.new('GeoLite2-Country.mmdb')
148
+
149
+ # Iterate over all networks
150
+ reader.each do |network, data|
151
+ puts "#{network}: #{data['country']['iso_code']}"
152
+ break # Remove this to see all networks
153
+ end
154
+
155
+ # Iterate over networks within a specific subnet (String CIDR notation)
156
+ reader.each('192.168.0.0/16') do |network, data|
157
+ puts "#{network}: #{data['city']['names']['en']}"
158
+ end
159
+
160
+ # Iterate over networks within a specific subnet (IPAddr object)
161
+ require 'ipaddr'
162
+ subnet = IPAddr.new('10.0.0.0/8')
163
+ reader.each(subnet) do |network, data|
164
+ puts "#{network}: #{data['country']['iso_code']}"
165
+ end
166
+
167
+ # Use Enumerable methods
168
+ countries = reader.map { |network, data| data['country']['iso_code'] }.uniq
169
+ puts "Unique countries: #{countries.size}"
170
+
171
+ reader.close
172
+ ```
173
+
174
+ ## API Documentation
175
+
176
+ ### `MaxMind::DB::Rust::Reader`
177
+
178
+ #### `new(database_path, options = {})`
179
+
180
+ Create a new Reader instance.
181
+
182
+ **Parameters:**
183
+
184
+ - `database_path` (String): Path to the MaxMind DB file
185
+ - `options` (Hash): Optional configuration
186
+ - `:mode` (Symbol): One of `:MODE_AUTO`, `:MODE_MEMORY`, or `:MODE_MMAP`
187
+
188
+ **Returns:** Reader instance
189
+
190
+ **Raises:**
191
+
192
+ - `Errno::ENOENT`: If the database file does not exist
193
+ - `MaxMind::DB::Rust::InvalidDatabaseError`: If the file is not a valid MaxMind DB
194
+
195
+ #### `get(ip_address)`
196
+
197
+ Look up an IP address in the database.
198
+
199
+ **Parameters:**
200
+
201
+ - `ip_address` (String or IPAddr): The IP address to look up
202
+
203
+ **Returns:** Hash with the record data, or `nil` if not found
204
+
205
+ **Raises:**
206
+
207
+ - `ArgumentError`: If looking up IPv6 in an IPv4-only database
208
+ - `MaxMind::DB::Rust::InvalidDatabaseError`: If the database is corrupt
209
+
210
+ #### `get_with_prefix_length(ip_address)`
211
+
212
+ Look up an IP address and return the prefix length.
213
+
214
+ **Parameters:**
215
+
216
+ - `ip_address` (String or IPAddr): The IP address to look up
217
+
218
+ **Returns:** Array `[record, prefix_length]` where record is a Hash or `nil`
219
+
220
+ #### `metadata()`
221
+
222
+ Get metadata about the database.
223
+
224
+ **Returns:** `MaxMind::DB::Rust::Metadata` instance
225
+
226
+ #### `close()`
227
+
228
+ Close the database and release resources.
229
+
230
+ #### `closed()`
231
+
232
+ Check if the database has been closed.
233
+
234
+ **Returns:** Boolean
235
+
236
+ #### `each(network = nil) { |network, data| ... }`
237
+
238
+ Iterate over networks in the database.
239
+
240
+ **Parameters:**
241
+
242
+ - `network` (String or IPAddr, optional): Network CIDR to iterate within (e.g., "192.168.0.0/16"). If omitted, iterates over all networks in the database.
243
+
244
+ **Yields:** IPAddr network and Hash data for each entry
245
+
246
+ **Returns:** Enumerator if no block given
247
+
248
+ **Raises:**
249
+
250
+ - `ArgumentError`: If network CIDR is invalid or IPv6 network specified for IPv4-only database
251
+
252
+ ### `MaxMind::DB::Rust::Metadata`
253
+
254
+ Metadata attributes:
255
+
256
+ - `binary_format_major_version` - Major version of the binary format
257
+ - `binary_format_minor_version` - Minor version of the binary format
258
+ - `build_epoch` - Unix timestamp when the database was built
259
+ - `database_type` - Type of database (e.g., "GeoIP2-City")
260
+ - `description` - Hash of locale codes to descriptions
261
+ - `ip_version` - 4 for IPv4-only, 6 for IPv4/IPv6 support
262
+ - `languages` - Array of supported locale codes
263
+ - `node_count` - Number of nodes in the search tree
264
+ - `record_size` - Record size in bits (24, 28, or 32)
265
+ - `node_byte_size` - Size of a node in bytes
266
+ - `search_tree_size` - Size of the search tree in bytes
267
+
268
+ ### Constants
269
+
270
+ - `MaxMind::DB::Rust::MODE_AUTO` - Automatically choose the best mode (uses MMAP)
271
+ - `MaxMind::DB::Rust::MODE_MEMORY` - Load entire database into memory
272
+ - `MaxMind::DB::Rust::MODE_MMAP` - Use memory-mapped file I/O (recommended)
273
+
274
+ ### Exceptions
275
+
276
+ - `MaxMind::DB::Rust::InvalidDatabaseError` - Raised when the database file is corrupt or invalid
277
+
278
+ ## Comparison with Official Gem
279
+
280
+ | Feature | maxmind-db (official) | maxmind-db-rust (this gem) |
281
+ | ---------------- | --------------------- | -------------------------- |
282
+ | Implementation | Pure Ruby | Rust with Ruby bindings |
283
+ | Performance | Baseline | 10-50x faster |
284
+ | API | MaxMind::DB | MaxMind::DB::Rust |
285
+ | MODE_FILE | ✓ | ✗ |
286
+ | MODE_MEMORY | ✓ | ✓ |
287
+ | MODE_AUTO | ✓ | ✓ |
288
+ | MODE_MMAP | ✗ | ✓ |
289
+ | Iterator support | ✗ | ✓ |
290
+ | Thread-safe | ✓ | ✓ |
291
+
292
+ ## Performance
293
+
294
+ Expected performance characteristics (will vary based on hardware):
295
+
296
+ - Single-threaded lookups: 300,000 - 500,000 lookups/second
297
+ - Significantly faster than pure Ruby implementations
298
+ - Memory-mapped mode (MMAP) provides best performance
299
+ - Fully thread-safe for concurrent lookups
300
+
301
+ ## Development
302
+
303
+ Interested in contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed developer documentation, including:
304
+
305
+ - Development setup and prerequisites
306
+ - Building and testing the extension
307
+ - Code quality guidelines
308
+ - Project structure
309
+ - Submitting changes
310
+
311
+ ### Quick Start
312
+
313
+ ```bash
314
+ git clone https://github.com/oschwald/maxmind-db-rust-ruby.git
315
+ cd maxmind-db-rust-ruby
316
+ git submodule update --init --recursive
317
+ bundle install
318
+ bundle exec rake compile
319
+ bundle exec rake test
320
+ ```
321
+
322
+ ## Contributing
323
+
324
+ 1. Fork it
325
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
326
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
327
+ 4. Push to the branch (`git push origin my-new-feature`)
328
+ 5. Create a new Pull Request
329
+
330
+ ## License
331
+
332
+ This software is licensed under the ISC License. See the LICENSE file for details.
333
+
334
+ ## Support
335
+
336
+ - **Issues**: https://github.com/oschwald/maxmind-db-rust-ruby/issues
337
+ - **Documentation**: https://www.rubydoc.info/gems/maxmind-db-rust
338
+
339
+ ## Credits
340
+
341
+ This gem uses the [maxminddb](https://github.com/oschwald/maxminddb-rust) Rust crate for the core MaxMind DB reading functionality.
342
+
343
+ Built with [magnus](https://github.com/matsadler/magnus) and [rb-sys](https://github.com/oxidize-rb/rb-sys).
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'maxmind/db/maxmind_db_rust'
5
+
6
+ module MaxMind
7
+ module DB
8
+ module Rust
9
+ # The native extension defines:
10
+ # - Reader class
11
+ # - Metadata class
12
+ # - InvalidDatabaseError exception
13
+ # - MODE_AUTO, MODE_MEMORY, MODE_MMAP constants
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'maxmind/db/maxmind_db_rust'
5
+
6
+ module MaxMind
7
+ # Check if DB is already defined as a Class (official gem)
8
+ if const_defined?(:DB) && DB.is_a?(Class)
9
+ # Official gem loaded - Rust module is already attached to the class by native extension
10
+ # Just add documentation here
11
+ class << DB
12
+ # The Rust module provides a high-performance Rust-based implementation for reading
13
+ # {MaxMind DB files}[https://maxmind.github.io/MaxMind-DB/].
14
+ #
15
+ # MaxMind DB is a binary file format that stores data indexed by IP address
16
+ # subnets (IPv4 or IPv6).
17
+ #
18
+ # This is a Rust-based implementation that provides significant performance
19
+ # improvements over pure Ruby implementations while maintaining API compatibility
20
+ # with the official MaxMind::DB gem.
21
+ #
22
+ # == Example
23
+ #
24
+ # require 'maxmind/db/rust'
25
+ #
26
+ # reader = MaxMind::DB::Rust::Reader.new(
27
+ # 'GeoIP2-City.mmdb',
28
+ # mode: MaxMind::DB::Rust::MODE_MEMORY
29
+ # )
30
+ #
31
+ # record = reader.get('1.1.1.1')
32
+ # if record.nil?
33
+ # puts '1.1.1.1 was not found in the database'
34
+ # else
35
+ # puts record['country']['iso_code']
36
+ # puts record['country']['names']['en']
37
+ # end
38
+ #
39
+ # reader.close
40
+ #
41
+ # == Using the Iterator
42
+ #
43
+ # require 'maxmind/db/rust'
44
+ #
45
+ # reader = MaxMind::DB::Rust::Reader.new('GeoLite2-Country.mmdb')
46
+ #
47
+ # # Iterate over all networks in the database
48
+ # reader.each do |network, data|
49
+ # puts "#{network}: #{data['country']['iso_code']}"
50
+ # end
51
+ #
52
+ # # Iterate over networks within a specific subnet
53
+ # reader.each('192.168.0.0/16') do |network, data|
54
+ # puts "#{network}: #{data['city']['names']['en']}"
55
+ # end
56
+ #
57
+ # # Also accepts IPAddr objects
58
+ # subnet = IPAddr.new('10.0.0.0/8')
59
+ # reader.each(subnet) do |network, data|
60
+ # puts "#{network}: #{data['country']['iso_code']}"
61
+ # end
62
+ #
63
+ # reader.close
64
+ #
65
+ # The Rust module (MaxMind::DB::Rust) defines:
66
+ # - Reader class
67
+ # - Metadata class
68
+ # - InvalidDatabaseError exception
69
+ # - MODE_AUTO, MODE_MEMORY, MODE_MMAP constants
70
+ end
71
+ else
72
+ # Official gem not loaded - define DB as a module
73
+ module DB
74
+ # Rust provides a high-performance Rust-based implementation for reading
75
+ # {MaxMind DB files}[https://maxmind.github.io/MaxMind-DB/].
76
+ #
77
+ # MaxMind DB is a binary file format that stores data indexed by IP address
78
+ # subnets (IPv4 or IPv6).
79
+ #
80
+ # This is a Rust-based implementation that provides significant performance
81
+ # improvements over pure Ruby implementations while maintaining API compatibility
82
+ # with the official MaxMind::DB gem.
83
+ #
84
+ # == Example
85
+ #
86
+ # require 'maxmind/db/rust'
87
+ #
88
+ # reader = MaxMind::DB::Rust::Reader.new(
89
+ # 'GeoIP2-City.mmdb',
90
+ # mode: MaxMind::DB::Rust::MODE_MEMORY
91
+ # )
92
+ #
93
+ # record = reader.get('1.1.1.1')
94
+ # if record.nil?
95
+ # puts '1.1.1.1 was not found in the database'
96
+ # else
97
+ # puts record['country']['iso_code']
98
+ # puts record['country']['names']['en']
99
+ # end
100
+ #
101
+ # reader.close
102
+ #
103
+ # == Using the Iterator
104
+ #
105
+ # require 'maxmind/db/rust'
106
+ #
107
+ # reader = MaxMind::DB::Rust::Reader.new('GeoLite2-Country.mmdb')
108
+ #
109
+ # # Iterate over all networks in the database
110
+ # reader.each do |network, data|
111
+ # puts "#{network}: #{data['country']['iso_code']}"
112
+ # end
113
+ #
114
+ # # Iterate over networks within a specific subnet
115
+ # reader.each('192.168.0.0/16') do |network, data|
116
+ # puts "#{network}: #{data['city']['names']['en']}"
117
+ # end
118
+ #
119
+ # # Also accepts IPAddr objects
120
+ # subnet = IPAddr.new('10.0.0.0/8')
121
+ # reader.each(subnet) do |network, data|
122
+ # puts "#{network}: #{data['country']['iso_code']}"
123
+ # end
124
+ #
125
+ # reader.close
126
+ module Rust
127
+ # The native extension defines:
128
+ # - Reader class
129
+ # - Metadata class
130
+ # - InvalidDatabaseError exception
131
+ # - MODE_AUTO, MODE_MEMORY, MODE_MMAP constants
132
+ end
133
+ end
134
+ end
135
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: maxmind-db-rust
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ platform: x86_64-linux
6
+ authors:
7
+ - Gregory Oschwald
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake-compiler-dock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.36'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.36'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-performance
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-thread_safety
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.6'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.6'
139
+ description: An unofficial high-performance Rust-based gem for reading MaxMind DB
140
+ files. Provides API compatibility with the official maxmind-db gem while leveraging
141
+ Rust for superior performance. This library is not endorsed by MaxMind.
142
+ email: oschwald@gmail.com
143
+ executables: []
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - CHANGELOG.md
148
+ - CONTRIBUTING.md
149
+ - LICENSE
150
+ - README.md
151
+ - ext/maxmind_db_rust/lib/maxmind/db/rust.rb
152
+ - lib/maxmind/db/3.2/maxmind_db_rust.so
153
+ - lib/maxmind/db/3.3/maxmind_db_rust.so
154
+ - lib/maxmind/db/3.4/maxmind_db_rust.so
155
+ - lib/maxmind/db/rust.rb
156
+ homepage: https://github.com/oschwald/maxmind-db-rust-ruby
157
+ licenses:
158
+ - ISC
159
+ metadata:
160
+ bug_tracker_uri: https://github.com/oschwald/maxmind-db-rust-ruby/issues
161
+ changelog_uri: https://github.com/oschwald/maxmind-db-rust-ruby/blob/main/CHANGELOG.md
162
+ documentation_uri: https://www.rubydoc.info/gems/maxmind-db-rust
163
+ homepage_uri: https://github.com/oschwald/maxmind-db-rust-ruby
164
+ source_code_uri: https://github.com/oschwald/maxmind-db-rust-ruby
165
+ rubygems_mfa_required: 'true'
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '3.2'
175
+ - - "<"
176
+ - !ruby/object:Gem::Version
177
+ version: 3.5.dev
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubygems_version: 3.5.23
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Unofficial high-performance Rust-based MaxMind DB reader for Ruby
188
+ test_files: []