blob: d25abf78495be6d8115acf85ee877941094d35ee (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
# frozen_string_literal: true
module Net
module Hippie
# Rust backend integration and availability detection.
#
# The RustBackend module manages the optional high-performance Rust HTTP client
# backend. It provides automatic detection of Rust extension availability and
# environment-based enabling/disabling of the Rust backend.
#
# == Backend Selection Logic
#
# 1. Check if NET_HIPPIE_RUST environment variable is set to 'true'
# 2. Verify that the Rust extension (net_hippie_ext) can be loaded
# 3. If both conditions are met, use RustConnection
# 4. Otherwise, fall back to RubyConnection
#
# == Performance Benefits
#
# When enabled, the Rust backend provides:
# * Significantly faster HTTP requests using reqwest
# * Better concurrency with Tokio async runtime
# * Lower memory usage with zero-cost abstractions
# * Type safety with compile-time guarantees
#
# @since 2.0.0
#
# == Environment Configuration
#
# # Enable Rust backend
# ENV['NET_HIPPIE_RUST'] = 'true'
#
# # Check availability and status
# puts "Rust available: #{Net::Hippie::RustBackend.available?}"
# puts "Rust enabled: #{Net::Hippie::RustBackend.enabled?}"
#
# @see RUST_BACKEND.md Detailed setup and usage documentation
module RustBackend
@rust_available = nil
# Checks if the Rust extension is available for loading.
#
# This method attempts to require the 'net_hippie_ext' native extension
# and caches the result. The extension is built from Rust source code
# using Magnus for Ruby-Rust integration.
#
# @return [Boolean] true if Rust extension loaded successfully
# @since 2.0.0
#
# @example Check Rust availability
# if Net::Hippie::RustBackend.available?
# puts "Rust backend ready!"
# else
# puts "Using Ruby backend (Rust not available)"
# end
def self.available?
return @rust_available unless @rust_available.nil?
@rust_available = begin
require 'net_hippie_ext'
true
rescue LoadError
false
end
end
# Checks if the Rust backend is both available and enabled.
#
# Returns true only when:
# 1. NET_HIPPIE_RUST environment variable is set to 'true'
# 2. The Rust extension is available (compiled and loadable)
#
# @return [Boolean] true if Rust backend should be used
# @since 2.0.0
#
# @example Check if Rust backend will be used
# ENV['NET_HIPPIE_RUST'] = 'true'
# if Net::Hippie::RustBackend.enabled?
# puts "All HTTP requests will use Rust backend"
# else
# puts "Falling back to Ruby backend"
# end
def self.enabled?
ENV['NET_HIPPIE_RUST'] == 'true' && available?
end
# Adapter that makes Rust HTTP responses compatible with Net::HTTPResponse interface.
#
# The ResponseAdapter provides a compatibility layer between Rust HTTP responses
# and Ruby's Net::HTTPResponse objects. This ensures that existing code works
# unchanged when switching between Ruby and Rust backends.
#
# == Compatibility Features
#
# * Status code access via #code method
# * Response body access via #body method
# * Header access via #[] method
# * Response class detection via #class method
# * Type checking via #is_a? and #kind_of?
#
# @since 2.0.0
#
# == Supported Response Classes
#
# * Net::HTTPOK (200)
# * Net::HTTPCreated (201)
# * Net::HTTPRedirection (3xx)
# * Net::HTTPClientError (4xx)
# * Net::HTTPServerError (5xx)
#
# @see Net::HTTPResponse The Ruby standard library response interface
class ResponseAdapter
# Creates a new response adapter from a Rust HTTP response.
#
# @param rust_response [RustResponse] The Rust HTTP response object
# @since 2.0.0
def initialize(rust_response)
@rust_response = rust_response
@code = rust_response.code
@body = rust_response.body
end
# Returns the HTTP status code.
#
# @return [String] HTTP status code (e.g., "200", "404")
# @since 2.0.0
def code
@code
end
# Returns the response body content.
#
# @return [String] HTTP response body
# @since 2.0.0
def body
@body
end
# Retrieves a response header value by name.
#
# @param header_name [String, Symbol] Header name (case-insensitive)
# @return [String, nil] Header value or nil if not found
# @since 2.0.0
#
# @example Get content type
# content_type = response['Content-Type']
# location = response[:location]
def [](header_name)
@rust_response[header_name.to_s]
end
# Returns the appropriate Net::HTTP response class based on status code.
#
# Maps HTTP status codes to their corresponding Net::HTTP class constants
# to maintain compatibility with Ruby HTTP library expectations.
#
# @return [Class] Net::HTTP response class constant
# @since 2.0.0
#
# @example Check response type
# response.class # => Net::HTTPOK (for 200 status)
# response.class # => Net::HTTPNotFound (for 404 status)
def class
case @code.to_i
when 200
Net::HTTPOK
when 201
Net::HTTPCreated
when 300..399
Net::HTTPRedirection
when 400..499
Net::HTTPClientError
when 500..599
Net::HTTPServerError
else
Net::HTTPResponse
end
end
# Checks if this response is an instance of the given class.
#
# Provides compatibility with Ruby's type checking by delegating
# to the mapped response class while supporting normal inheritance.
#
# @param klass [Class] Class to check against
# @return [Boolean] true if response matches the class
# @since 2.0.0
#
# @example Type checking
# response.is_a?(Net::HTTPOK) # => true (for 200 status)
# response.is_a?(Net::HTTPRedirection) # => true (for 3xx status)
def is_a?(klass)
self.class == klass || super
end
# Alias for #is_a? to maintain Ruby compatibility.
#
# @param klass [Class] Class to check against
# @return [Boolean] true if response matches the class
# @since 2.0.0
def kind_of?(klass)
is_a?(klass)
end
end
end
end
end
|