fast_cuid2 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 674b326baeddf83d78dd24637f903fbcf6a823c46cb0e2d951409d0b5b539b94
4
+ data.tar.gz: f26f14bec785defaa804cb62e6602e78946f7c331dab1e167d7234165f5d4f93
5
+ SHA512:
6
+ metadata.gz: a416b5eac1fcff9cac876689482c641f9df932d49c5424294b55b94d7e462dd83cd4f43f858370dd9c3768668927e2889cdae6b889945d22528b03b1369db6be
7
+ data.tar.gz: 5b3efb13674b84b39aefa5cad16ba47d040d90a0817fd25118cd29e88076064b8c6efd90d8d58ac63a1751a9c446e9b8739039534ce5b05116c86e429e8570a2
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # FastCuid2 🚀
2
+
3
+ A high-performance CUID2 (Collision-resistant Unique ID) generator for Ruby, implemented in C for maximum speed while maintaining cryptographic security.
4
+
5
+ ## What is CUID2? 🤔
6
+
7
+ CUID2 is the next generation of collision-resistant ids, designed to be:
8
+ - 🔒 Secure: Uses cryptographically secure random numbers
9
+ - 📏 Shorter: 24 characters vs CUID1's 25
10
+ - 🔗 URL-safe: Uses a restricted character set
11
+ - ⏰ Time-sortable: Includes a timestamp component
12
+ - 🎯 Unique: Has a negligible chance of collision
13
+
14
+ ## Installation 💿
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'fast_cuid2'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ ```bash
25
+ $ bundle install
26
+ ```
27
+
28
+ Or install it yourself as:
29
+
30
+ ```bash
31
+ $ gem install fast_cuid2
32
+ ```
33
+
34
+ ## Usage 🛠️
35
+
36
+ ### Basic Usage 💡
37
+
38
+ ```ruby
39
+ require 'fast_cuid2'
40
+
41
+ # Generate a new CUID2
42
+ id = FastCuid2.generate
43
+ puts id # => "k2zt4qxvz5..."
44
+
45
+ # Use as a before_create callback in your models
46
+ class User < ApplicationRecord
47
+ before_create :set_cuid2
48
+
49
+ private
50
+ def set_cuid2
51
+ self.id = FastCuid2.generate
52
+ end
53
+ end
54
+ ```
55
+
56
+ ### Database Migrations 🗄️
57
+
58
+ Example migration for creating a new table with CUID2:
59
+
60
+ ```ruby
61
+ class CreateUsers < ActiveRecord::Migration[7.0]
62
+ def change
63
+ create_table :users, id: false do |t|
64
+ t.string :id, primary_key: true, null: false, limit: 24
65
+ t.timestamps
66
+ end
67
+ end
68
+ end
69
+ ```
70
+
71
+ Adding a CUID2 column to an existing table:
72
+
73
+ ```ruby
74
+ class AddReferenceToPosts < ActiveRecord::Migration[7.0]
75
+ def change
76
+ add_column :posts, :reference_id, :string, limit: 24
77
+ add_index :posts, :reference_id, unique: true
78
+ end
79
+ end
80
+ ```
81
+
82
+ ## CUID2 Format 📋
83
+
84
+ Each CUID2 is a 24-character string that:
85
+ - 📝 Always starts with a letter
86
+ - ⌨️ Uses only lowercase letters and numbers (excluding i, l, o, u)
87
+ - 🕒 Includes a time component for rough sorting
88
+ - 🔐 Has cryptographically secure random data
89
+
90
+ ## Performance ⚡
91
+
92
+ FastCuid2 is implemented in C for maximum performance. It uses:
93
+ - 🔒 OpenSSL's CSPRNG for secure random numbers
94
+ - ⚙️ Optimized bit operations
95
+ - 💾 Minimal memory allocations
96
+ - 🔄 Thread-safe implementation
97
+
98
+ ## Development 👩‍💻
99
+
100
+ After checking out the repo, run:
101
+
102
+ ```bash
103
+ $ bundle install
104
+ $ rake compile # Builds the C extension
105
+ $ rake spec # Runs the tests
106
+ ```
107
+
108
+ ## Contributing 🤝
109
+
110
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sebyx07/fast_cuid2. This project is intended to be a safe, welcoming space for collaboration.
111
+
112
+ ## License 📜
113
+
114
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
115
+
116
+ ## Code of Conduct 🤝
117
+
118
+ Everyone interacting in the FastCuid2 project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/sebyx07/fast_cuid2/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ # Add optimization flags
6
+ $CFLAGS << ' -O3 -Wall -Wextra'
7
+
8
+ # Check for required headers
9
+ have_header('ruby.h')
10
+ have_library('crypto')
11
+ have_header('openssl/rand.h')
12
+
13
+ extension_name = 'fast_cuid2/fast_cuid2'
14
+ dir_config(extension_name)
15
+
16
+ create_makefile(extension_name)
@@ -0,0 +1,119 @@
1
+ #include <ruby.h>
2
+ #include <time.h>
3
+ #include <openssl/rand.h>
4
+ #include <string.h>
5
+
6
+ /* Constants for CUID2 generation */
7
+ #define CUID2_LENGTH 24
8
+ #define CUID2_BUFFER_SIZE (CUID2_LENGTH + 1)
9
+ #define TIMESTAMP_LENGTH 6
10
+ #define RANDOM_BYTES_LENGTH 12
11
+ #define BASE32_CHARS_LENGTH 32
12
+ #define TIMESTAMP_BITS 5
13
+ #define RANDOM_CHUNK_SIZE 2
14
+ #define BASE32_CHARS_PER_CHUNK 3
15
+
16
+ /* Base32 alphabet excluding i, l, o, u for better readability */
17
+ static const char BASE32_CHARS[] = "0123456789abcdefghjkmnpqrstvwxyz";
18
+
19
+ static VALUE rb_mFastCuid2;
20
+
21
+ /**
22
+ * Encodes an integer into base32 representation.
23
+ * @param num The number to encode
24
+ * @param output The buffer to write to
25
+ * @param length The number of characters to write
26
+ */
27
+ static void encode_base32(uint64_t num, char *output, int length) {
28
+ for (int i = length - 1; i >= 0; i--) {
29
+ output[i] = BASE32_CHARS[num & 0x1f];
30
+ num >>= TIMESTAMP_BITS;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Generates cryptographically secure random bytes.
36
+ * @param buf Buffer to store random bytes
37
+ * @param length Number of random bytes to generate
38
+ * @raises RuntimeError if random byte generation fails
39
+ */
40
+ static void generate_random_bytes(unsigned char *buf, int length) {
41
+ if (RAND_bytes(buf, length) != 1) {
42
+ rb_raise(rb_eRuntimeError, "Failed to generate secure random bytes");
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Ensures the first character of the CUID2 is a letter.
48
+ * @param cuid The CUID2 string to modify
49
+ */
50
+ static void ensure_first_char_is_letter(char *cuid) {
51
+ if (cuid[0] >= '0' && cuid[0] <= '9') {
52
+ int offset = 10 + (cuid[0] - '0'); // Map digit to letter range
53
+ cuid[0] = BASE32_CHARS[offset];
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Generates a CUID2 (Collision-resistant Unique IDentifier).
59
+ * Format: <6 chars timestamp><18 chars random>
60
+ * @return [String] A 24-character CUID2
61
+ * @raise [RuntimeError] If generation fails
62
+ */
63
+ static VALUE rb_generate_cuid2(VALUE self) {
64
+ char cuid[CUID2_BUFFER_SIZE] = {0};
65
+ struct timespec ts;
66
+ unsigned char random_bytes[RANDOM_BYTES_LENGTH];
67
+
68
+ // Get current timestamp in milliseconds
69
+ if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
70
+ rb_raise(rb_eRuntimeError, "Failed to get system time");
71
+ }
72
+ uint64_t timestamp = (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
73
+
74
+ // Generate random bytes
75
+ generate_random_bytes(random_bytes, RANDOM_BYTES_LENGTH);
76
+
77
+ // Encode timestamp (first 6 chars)
78
+ encode_base32(timestamp, cuid, TIMESTAMP_LENGTH);
79
+
80
+ // Fill remaining 18 chars with random data
81
+ // Process 2 bytes at a time to generate 3 base32 chars
82
+ for (int i = 0; i < RANDOM_BYTES_LENGTH; i += RANDOM_CHUNK_SIZE) {
83
+ uint32_t rand_chunk =
84
+ ((uint32_t)random_bytes[i] << 8) |
85
+ ((uint32_t)random_bytes[i + 1]);
86
+ encode_base32(rand_chunk, cuid + TIMESTAMP_LENGTH + (i / RANDOM_CHUNK_SIZE) * BASE32_CHARS_PER_CHUNK, BASE32_CHARS_PER_CHUNK);
87
+ }
88
+
89
+ ensure_first_char_is_letter(cuid);
90
+
91
+ return rb_str_new2(cuid);
92
+ }
93
+
94
+ /**
95
+ * Validates a CUID2 string.
96
+ * @param str [String] The string to validate
97
+ * @return [Boolean] true if valid CUID2, false otherwise
98
+ */
99
+ static VALUE rb_validate_cuid2(VALUE self, VALUE str) {
100
+ Check_Type(str, T_STRING);
101
+
102
+ if (RSTRING_LEN(str) != CUID2_LENGTH) return Qfalse;
103
+
104
+ const char *cuid = StringValuePtr(str);
105
+ for (int i = 0; i < CUID2_LENGTH; i++) {
106
+ if (!strchr(BASE32_CHARS, cuid[i])) return Qfalse;
107
+ }
108
+
109
+ // First character must be a letter
110
+ if (strchr("0123456789", cuid[0])) return Qfalse;
111
+
112
+ return Qtrue;
113
+ }
114
+
115
+ void Init_fast_cuid2(void) {
116
+ rb_mFastCuid2 = rb_define_module("FastCuid2");
117
+ rb_define_singleton_method(rb_mFastCuid2, "generate", rb_generate_cuid2, 0);
118
+ rb_define_singleton_method(rb_mFastCuid2, "valid?", rb_validate_cuid2, 1);
119
+ }
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/gem/fast_cuid2/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'fast_cuid2'
7
+ spec.version = FastCuid2::VERSION
8
+ spec.authors = ['sebi']
9
+ spec.email = ['gore.sebyx@yahoo.com']
10
+
11
+ spec.summary = 'Fast CUID2 generator with C extension'
12
+ spec.description = 'High-performance CUID2 (Collision-resistant Unique ID) generator ' \
13
+ 'implemented in C for maximum speed while maintaining cryptographic security.'
14
+ spec.homepage = 'https://github.com/sebyx07/fast_cuid2'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 3.0.0'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = spec.homepage
20
+
21
+ # Include C extension
22
+ spec.extensions = ['ext/fast_cuid2/extconf.rb']
23
+
24
+ # Include both lib and ext directories
25
+ spec.files = Dir.glob('{lib,ext}/{**/*,*}') +
26
+ ['README.md', File.basename(__FILE__)]
27
+
28
+ # Set require paths for both the gem and extension
29
+ spec.require_paths = %w[lib/gem lib]
30
+
31
+ # Development dependencies
32
+ spec.add_development_dependency 'rake', '~> 13.0'
33
+ spec.add_development_dependency 'rake-compiler', '~> 1.2'
34
+ end
Binary file
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FastCuid2
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob(File.join(File.dirname(__FILE__), 'fast_cuid2', '**', '*.rb')).each do |file|
4
+ require file
5
+ end
6
+
7
+ begin
8
+ require 'fast_cuid2/fast_cuid2'
9
+ rescue LoadError
10
+ puts 'Error loading fast_cuid2 extension'
11
+ end
12
+
13
+ module FastCuid2
14
+ class Error < StandardError; end
15
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fast_cuid2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - sebi
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-02-10 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '13.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '13.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake-compiler
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.2'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ description: High-performance CUID2 (Collision-resistant Unique ID) generator implemented
41
+ in C for maximum speed while maintaining cryptographic security.
42
+ email:
43
+ - gore.sebyx@yahoo.com
44
+ executables: []
45
+ extensions:
46
+ - ext/fast_cuid2/extconf.rb
47
+ extra_rdoc_files: []
48
+ files:
49
+ - README.md
50
+ - ext/fast_cuid2/extconf.rb
51
+ - ext/fast_cuid2/fast_cuid2.c
52
+ - fast_cuid2.gemspec
53
+ - lib/fast_cuid2/fast_cuid2.so
54
+ - lib/gem/fast_cuid2.rb
55
+ - lib/gem/fast_cuid2/version.rb
56
+ homepage: https://github.com/sebyx07/fast_cuid2
57
+ licenses:
58
+ - MIT
59
+ metadata:
60
+ homepage_uri: https://github.com/sebyx07/fast_cuid2
61
+ source_code_uri: https://github.com/sebyx07/fast_cuid2
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib/gem
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 3.0.0
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 3.6.3
78
+ specification_version: 4
79
+ summary: Fast CUID2 generator with C extension
80
+ test_files: []