[ruby/yarp] Treat yp_buffer_t as an opaque pointer
Right now, we have to keep the buffer FFI object in sync with the definition of yp_buffer_t because we access its fields directly. If we add more fields or change the order, things will get out of sync. Instead, let's treat yp_buffer_t as an opaque pointer and access its fields through accessor functions directly. This is more consistent with how we handle strings anyway. https://github.com/ruby/yarp/commit/878d845eff
This commit is contained in:
parent
75a4767525
commit
81d715099c
Notes:
git
2023-08-17 16:59:16 +00:00
@ -75,7 +75,10 @@ module YARP
|
|||||||
|
|
||||||
load_exported_functions_from(
|
load_exported_functions_from(
|
||||||
"yarp/util/yp_buffer.h",
|
"yarp/util/yp_buffer.h",
|
||||||
|
"yp_buffer_sizeof",
|
||||||
"yp_buffer_init",
|
"yp_buffer_init",
|
||||||
|
"yp_buffer_value",
|
||||||
|
"yp_buffer_length",
|
||||||
"yp_buffer_free"
|
"yp_buffer_free"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -88,34 +91,49 @@ module YARP
|
|||||||
"yp_string_sizeof"
|
"yp_string_sizeof"
|
||||||
)
|
)
|
||||||
|
|
||||||
# This object represents a yp_buffer_t. Its structure must be kept in sync
|
# This object represents a yp_buffer_t. We only use it as an opaque pointer,
|
||||||
# with the C version.
|
# so it doesn't need to know the fields of yp_buffer_t.
|
||||||
class YPBuffer < FFI::Struct
|
class YPBuffer
|
||||||
layout value: :pointer, length: :size_t, capacity: :size_t
|
SIZEOF = LibRubyParser.yp_buffer_sizeof
|
||||||
|
|
||||||
# Read the contents of the buffer into a String object and return it.
|
attr_reader :pointer
|
||||||
def to_ruby_string
|
|
||||||
self[:value].read_string(self[:length])
|
def initialize(pointer)
|
||||||
|
@pointer = pointer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def value
|
||||||
|
LibRubyParser.yp_buffer_value(pointer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
LibRubyParser.yp_buffer_length(pointer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def read
|
||||||
|
value.read_string(length)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Initialize a new buffer and yield it to the block. The buffer will be
|
# Initialize a new buffer and yield it to the block. The buffer will be
|
||||||
# automatically freed when the block returns.
|
# automatically freed when the block returns.
|
||||||
def self.with_buffer(&block)
|
def self.with(&block)
|
||||||
buffer = YPBuffer.new
|
pointer = FFI::MemoryPointer.new(SIZEOF)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
raise unless yp_buffer_init(buffer)
|
raise unless LibRubyParser.yp_buffer_init(pointer)
|
||||||
yield buffer
|
yield new(pointer)
|
||||||
ensure
|
ensure
|
||||||
yp_buffer_free(buffer)
|
LibRubyParser.yp_buffer_free(pointer)
|
||||||
buffer.pointer.free
|
pointer.free
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This object represents a yp_string_t. We only use it as an opaque pointer,
|
# This object represents a yp_string_t. We only use it as an opaque pointer,
|
||||||
# so it doesn't have to be an FFI::Struct.
|
# so it doesn't have to be an FFI::Struct.
|
||||||
class YPString
|
class YPString
|
||||||
|
SIZEOF = LibRubyParser.yp_string_sizeof
|
||||||
|
|
||||||
attr_reader :pointer
|
attr_reader :pointer
|
||||||
|
|
||||||
def initialize(pointer)
|
def initialize(pointer)
|
||||||
@ -133,23 +151,18 @@ module YARP
|
|||||||
def read
|
def read
|
||||||
source.read_string(length)
|
source.read_string(length)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# This is the size of a yp_string_t. It is returned by the yp_string_sizeof
|
|
||||||
# function which we call once to ensure we have sufficient space for the
|
|
||||||
# yp_string_t FFI pointer.
|
|
||||||
SIZEOF_YP_STRING = yp_string_sizeof
|
|
||||||
|
|
||||||
# Yields a yp_string_t pointer to the given block.
|
# Yields a yp_string_t pointer to the given block.
|
||||||
def self.with_string(filepath, &block)
|
def self.with(filepath, &block)
|
||||||
string = FFI::MemoryPointer.new(SIZEOF_YP_STRING)
|
pointer = FFI::MemoryPointer.new(SIZEOF)
|
||||||
|
|
||||||
begin
|
begin
|
||||||
raise unless yp_string_mapped_init(string, filepath)
|
raise unless LibRubyParser.yp_string_mapped_init(pointer, filepath)
|
||||||
yield YPString.new(string)
|
yield new(pointer)
|
||||||
ensure
|
ensure
|
||||||
yp_string_free(string)
|
LibRubyParser.yp_string_free(pointer)
|
||||||
string.free
|
pointer.free
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -162,10 +175,10 @@ module YARP
|
|||||||
VERSION = LibRubyParser.yp_version.read_string
|
VERSION = LibRubyParser.yp_version.read_string
|
||||||
|
|
||||||
def self.dump_internal(source, source_size, filepath)
|
def self.dump_internal(source, source_size, filepath)
|
||||||
LibRubyParser.with_buffer do |buffer|
|
LibRubyParser::YPBuffer.with do |buffer|
|
||||||
metadata = [filepath.bytesize, filepath.b, 0].pack("LA*L") if filepath
|
metadata = [filepath.bytesize, filepath.b, 0].pack("LA*L") if filepath
|
||||||
LibRubyParser.yp_parse_serialize(source, source_size, buffer, metadata)
|
LibRubyParser.yp_parse_serialize(source, source_size, buffer.pointer, metadata)
|
||||||
buffer.to_ruby_string
|
buffer.read
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
private_class_method :dump_internal
|
private_class_method :dump_internal
|
||||||
@ -177,24 +190,24 @@ module YARP
|
|||||||
|
|
||||||
# Mirror the YARP.dump_file API by using the serialization API.
|
# Mirror the YARP.dump_file API by using the serialization API.
|
||||||
def self.dump_file(filepath)
|
def self.dump_file(filepath)
|
||||||
LibRubyParser.with_string(filepath) do |string|
|
LibRubyParser::YPString.with(filepath) do |string|
|
||||||
dump_internal(string.source, string.length, filepath)
|
dump_internal(string.source, string.length, filepath)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Mirror the YARP.lex API by using the serialization API.
|
# Mirror the YARP.lex API by using the serialization API.
|
||||||
def self.lex(code, filepath = nil)
|
def self.lex(code, filepath = nil)
|
||||||
LibRubyParser.with_buffer do |buffer|
|
LibRubyParser::YPBuffer.with do |buffer|
|
||||||
LibRubyParser.yp_lex_serialize(code, code.bytesize, filepath, buffer)
|
LibRubyParser.yp_lex_serialize(code, code.bytesize, filepath, buffer.pointer)
|
||||||
|
Serialize.load_tokens(Source.new(code), buffer.read)
|
||||||
source = Source.new(code)
|
|
||||||
Serialize.load_tokens(source, buffer.to_ruby_string)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Mirror the YARP.lex_file API by using the serialization API.
|
# Mirror the YARP.lex_file API by using the serialization API.
|
||||||
def self.lex_file(filepath)
|
def self.lex_file(filepath)
|
||||||
LibRubyParser.with_string(filepath) { |string| lex(string.read, filepath) }
|
LibRubyParser::YPString.with(filepath) do |string|
|
||||||
|
lex(string.read, filepath)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Mirror the YARP.parse API by using the serialization API.
|
# Mirror the YARP.parse API by using the serialization API.
|
||||||
@ -206,6 +219,8 @@ module YARP
|
|||||||
# native strings instead of Ruby strings because it allows us to use mmap when
|
# native strings instead of Ruby strings because it allows us to use mmap when
|
||||||
# it is available.
|
# it is available.
|
||||||
def self.parse_file(filepath)
|
def self.parse_file(filepath)
|
||||||
LibRubyParser.with_string(filepath) { |string| parse(string.read, filepath) }
|
LibRubyParser::YPString.with(filepath) do |string|
|
||||||
|
parse(string.read, filepath)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -66,7 +66,7 @@ dump_input(yp_string_t *input, const char *filepath) {
|
|||||||
yp_node_t *node = yp_parse(&parser);
|
yp_node_t *node = yp_parse(&parser);
|
||||||
yp_serialize(&parser, node, &buffer);
|
yp_serialize(&parser, node, &buffer);
|
||||||
|
|
||||||
VALUE result = rb_str_new(buffer.value, buffer.length);
|
VALUE result = rb_str_new(yp_buffer_value(&buffer), yp_buffer_length(&buffer));
|
||||||
yp_node_destroy(&parser, node);
|
yp_node_destroy(&parser, node);
|
||||||
yp_buffer_free(&buffer);
|
yp_buffer_free(&buffer);
|
||||||
yp_parser_free(&parser);
|
yp_parser_free(&parser);
|
||||||
@ -483,7 +483,7 @@ parse_serialize_file_metadata(VALUE self, VALUE filepath, VALUE metadata) {
|
|||||||
if (!yp_string_mapped_init(&input, checked)) return Qnil;
|
if (!yp_string_mapped_init(&input, checked)) return Qnil;
|
||||||
|
|
||||||
yp_parse_serialize(yp_string_source(&input), yp_string_length(&input), &buffer, check_string(metadata));
|
yp_parse_serialize(yp_string_source(&input), yp_string_length(&input), &buffer, check_string(metadata));
|
||||||
VALUE result = rb_str_new(buffer.value, buffer.length);
|
VALUE result = rb_str_new(yp_buffer_value(&buffer), yp_buffer_length(&buffer));
|
||||||
|
|
||||||
yp_buffer_free(&buffer);
|
yp_buffer_free(&buffer);
|
||||||
return result;
|
return result;
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
#define YP_BUFFER_INITIAL_SIZE 1024
|
#define YP_BUFFER_INITIAL_SIZE 1024
|
||||||
|
|
||||||
|
// Return the size of the yp_buffer_t struct.
|
||||||
|
size_t
|
||||||
|
yp_buffer_sizeof(void) {
|
||||||
|
return sizeof(yp_buffer_t);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize a yp_buffer_t with its default values.
|
// Initialize a yp_buffer_t with its default values.
|
||||||
bool
|
bool
|
||||||
yp_buffer_init(yp_buffer_t *buffer) {
|
yp_buffer_init(yp_buffer_t *buffer) {
|
||||||
@ -12,6 +18,18 @@ yp_buffer_init(yp_buffer_t *buffer) {
|
|||||||
return buffer->value != NULL;
|
return buffer->value != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the value of the buffer.
|
||||||
|
char *
|
||||||
|
yp_buffer_value(yp_buffer_t *buffer) {
|
||||||
|
return buffer->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the length of the buffer.
|
||||||
|
size_t
|
||||||
|
yp_buffer_length(yp_buffer_t *buffer) {
|
||||||
|
return buffer->length;
|
||||||
|
}
|
||||||
|
|
||||||
// Append the given amount of space to the buffer.
|
// Append the given amount of space to the buffer.
|
||||||
static inline void
|
static inline void
|
||||||
yp_buffer_append_length(yp_buffer_t *buffer, size_t length) {
|
yp_buffer_append_length(yp_buffer_t *buffer, size_t length) {
|
||||||
|
@ -12,16 +12,24 @@
|
|||||||
// A yp_buffer_t is a simple memory buffer that stores data in a contiguous
|
// A yp_buffer_t is a simple memory buffer that stores data in a contiguous
|
||||||
// block of memory. It is used to store the serialized representation of a
|
// block of memory. It is used to store the serialized representation of a
|
||||||
// YARP tree.
|
// YARP tree.
|
||||||
// NOTE: keep in sync with YARP::LibRubyParser::Buffer in lib/yarp.rb
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *value;
|
char *value;
|
||||||
size_t length;
|
size_t length;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} yp_buffer_t;
|
} yp_buffer_t;
|
||||||
|
|
||||||
|
// Return the size of the yp_buffer_t struct.
|
||||||
|
YP_EXPORTED_FUNCTION size_t yp_buffer_sizeof(void);
|
||||||
|
|
||||||
// Initialize a yp_buffer_t with its default values.
|
// Initialize a yp_buffer_t with its default values.
|
||||||
YP_EXPORTED_FUNCTION bool yp_buffer_init(yp_buffer_t *buffer);
|
YP_EXPORTED_FUNCTION bool yp_buffer_init(yp_buffer_t *buffer);
|
||||||
|
|
||||||
|
// Return the value of the buffer.
|
||||||
|
YP_EXPORTED_FUNCTION char * yp_buffer_value(yp_buffer_t *buffer);
|
||||||
|
|
||||||
|
// Return the length of the buffer.
|
||||||
|
YP_EXPORTED_FUNCTION size_t yp_buffer_length(yp_buffer_t *buffer);
|
||||||
|
|
||||||
// Append the given amount of space as zeroes to the buffer.
|
// Append the given amount of space as zeroes to the buffer.
|
||||||
void yp_buffer_append_zeroes(yp_buffer_t *buffer, size_t length);
|
void yp_buffer_append_zeroes(yp_buffer_t *buffer, size_t length);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user