diff options
-rw-r--r-- | ext/ffi_c/AbstractMemory.c | 10 | ||||
-rw-r--r-- | ext/ffi_c/MappedType.c | 22 | ||||
-rw-r--r-- | ext/ffi_c/Pointer.c | 91 | ||||
-rw-r--r-- | ext/ffi_c/Type.c | 103 | ||||
-rw-r--r-- | ext/ffi_c/ffi.c | 5 | ||||
-rw-r--r-- | lib/ffi/pointer.rb | 42 | ||||
-rw-r--r-- | lib/ffi/types.rb | 22 |
7 files changed, 279 insertions, 16 deletions
diff --git a/ext/ffi_c/AbstractMemory.c b/ext/ffi_c/AbstractMemory.c index d12ca4d..a5afd9c 100644 --- a/ext/ffi_c/AbstractMemory.c +++ b/ext/ffi_c/AbstractMemory.c @@ -458,12 +458,12 @@ memory_get_bytes(VALUE self, VALUE offset, VALUE length) /* * call-seq: memory.put_bytes(offset, str, index=0, length=nil) - * Return string contained in memory. + * Put a string in memory. * @param [Numeric] offset point in buffer to start from * @param [String] str string to put to memory * @param [Numeric] index * @param [Numeric] length string's length in bytes. If nil, a (memory size - offset) length string is returned). - * @return [String] + * @return [self] * @raise {IndexError} if +length+ is too great * @raise {NullPointerError} if memory not initialized * @raise {RangeError} if +index+ is negative, or if index+length is greater than size of string @@ -521,7 +521,7 @@ memory_read_bytes(VALUE self, VALUE length) * @param [String] str string to put to memory * @param [Numeric] index * @param [Numeric] length string's length in bytes. If nil, a (memory size - offset) length string is returned). - * @return [String] + * @return [self] * equivalent to : * memory.put_bytes(0, str, index, length) */ @@ -681,7 +681,9 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI) */ VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject); rbffi_AbstractMemoryClass = classMemory; - /* Document-variable: FFI::AbstractMemory */ + /* + * Document-variable: FFI::AbstractMemory + */ rb_global_variable(&rbffi_AbstractMemoryClass); rb_define_alloc_func(classMemory, memory_allocate); diff --git a/ext/ffi_c/MappedType.c b/ext/ffi_c/MappedType.c index 61b6d65..7a77842 100644 --- a/ext/ffi_c/MappedType.c +++ b/ext/ffi_c/MappedType.c @@ -50,6 +50,12 @@ mapped_allocate(VALUE klass) return obj; } +/* + * call-seq: initialize(converter) + * @param [#native_type, #to_native, #from_native] converter +converter+ must respond to + * all these methods + * @return [self] + */ static VALUE mapped_initialize(VALUE self, VALUE rbConverter) { @@ -88,6 +94,11 @@ mapped_mark(MappedType* m) rb_gc_mark(m->rbConverter); } +/* + * call-seq: mapped_type.native_type + * @return [Type] + * Get native type of mapped type. + */ static VALUE mapped_native_type(VALUE self) { @@ -97,6 +108,10 @@ mapped_native_type(VALUE self) return m->rbType; } +/* + * call-seq: mapped_type.to_native(*args) + * @param args depends on {FFI::DataConverter} used to initialize +self+ + */ static VALUE mapped_to_native(int argc, VALUE* argv, VALUE self) { @@ -107,6 +122,10 @@ mapped_to_native(int argc, VALUE* argv, VALUE self) return rb_funcall2(m->rbConverter, id_to_native, argc, argv); } +/* + * call-seq: mapped_type.from_native(*args) + * @param args depends on {FFI::DataConverter} used to initialize +self+ + */ static VALUE mapped_from_native(int argc, VALUE* argv, VALUE self) { @@ -121,6 +140,9 @@ void rbffi_MappedType_Init(VALUE moduleFFI) { + /* + * Document-class: FFI::Type::Mapped + */ rbffi_MappedTypeClass = rb_define_class_under(rbffi_TypeClass, "Mapped", rbffi_TypeClass); rb_global_variable(&rbffi_MappedTypeClass); diff --git a/ext/ffi_c/Pointer.c b/ext/ffi_c/Pointer.c index 70f5af9..752b027 100644 --- a/ext/ffi_c/Pointer.c +++ b/ext/ffi_c/Pointer.c @@ -68,6 +68,13 @@ ptr_allocate(VALUE klass) return obj; } +/* + * call-seq: initialize(type, address) + * @param [Type] type type for pointer + * @param [Integer, Pointer] address base address for pointer, or another pointer + * @return [self] + * Create a new pointer from a {Type} and a base adresse or another {Pointer}. + */ static VALUE ptr_initialize(int argc, VALUE* argv, VALUE self) { @@ -117,6 +124,16 @@ ptr_initialize(int argc, VALUE* argv, VALUE self) return self; } +/* + * call-seq: ptr.initialize_copy(other) + * @param [Pointer] other source for cloning or dupping + * @return [self] + * @raise {RuntimeError} if +other+ is an unbounded memory area, or is unreable/unwritable + * @raise {NoMemError} if failed to allocate memory for new object + * DO NOT CALL THIS METHOD. + * + * This method is internally used by #dup and #clone. Memory contents is copied from +other+. + */ static VALUE ptr_initialize_copy(VALUE self, VALUE other) { @@ -179,6 +196,13 @@ slice(VALUE self, long offset, long size) return retval; } +/* + * Document-method: + + * call-seq: ptr + offset + * @param [Numeric] offset + * @return [Pointer] + * Return a new {Pointer} from an existing pointer and an +offset+. + */ static VALUE ptr_plus(VALUE self, VALUE offset) { @@ -190,12 +214,25 @@ ptr_plus(VALUE self, VALUE offset) return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off); } +/* + * call-seq: ptr.slice(offset, length) + * @param [Numeric] offset + * @param [Numeric] length + * @return [Pointer] + * Return a new {Pointer} from an existing one. This pointer points on same contents + * from +offset+ for a length +length+. + */ static VALUE ptr_slice(VALUE self, VALUE rbOffset, VALUE rbLength) { return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength)); } +/* + * call-seq: ptr.inspect + * @return [String] + * Inspect pointer object. + */ static VALUE ptr_inspect(VALUE self) { @@ -214,6 +251,12 @@ ptr_inspect(VALUE self) return rb_str_new2(buf); } +/* + * Document-method: null? + * call-seq: ptr.null? + * @return [Boolean] + * Return +true+ if +self+ is a {NULL} pointer. + */ static VALUE ptr_null_p(VALUE self) { @@ -224,6 +267,12 @@ ptr_null_p(VALUE self) return ptr->memory.address == NULL ? Qtrue : Qfalse; } +/* + * Document-method: == + * call-seq: ptr == other + * @param [Pointer] other + * Check equality between +self+ and +other+. Equality is tested on {#address}. + */ static VALUE ptr_equals(VALUE self, VALUE other) { @@ -234,6 +283,11 @@ ptr_equals(VALUE self, VALUE other) return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse; } +/* + * call-seq: ptr.address + * @return [Numeric] pointer's base address + * Return +self+'s base address (alias: #to_i). + */ static VALUE ptr_address(VALUE self) { @@ -250,6 +304,15 @@ ptr_address(VALUE self) # define SWAPPED_ORDER LITTLE_ENDIAN #endif +/* + * Get or set +self+'s endianness + * @overload ptr.order + * @return [:big, :little] endianness of +self+ + * @overload ptr.order(order) + * @param [Symbol] order endianness to set (+:little+, +:big+ or +:network+). +:big+ and +:network+ + * are synonymous. + * @return [self] + */ static VALUE ptr_order(int argc, VALUE* argv, VALUE self) { @@ -289,6 +352,11 @@ ptr_order(int argc, VALUE* argv, VALUE self) } +/* + * call-seq: ptr.free + * @return [self] + * Free memory pointed by +self+. + */ static VALUE ptr_free(VALUE self) { @@ -307,6 +375,12 @@ ptr_free(VALUE self) return self; } +/* + * call-seq: ptr.autorelease = autorelease + * @param [Boolean] autorelease + * @return [Boolean] +autorelease+ + * Set +autorelease+ attribute. See also Autorelease section. + */ static VALUE ptr_autorelease(VALUE self, VALUE autorelease) { @@ -318,6 +392,11 @@ ptr_autorelease(VALUE self, VALUE autorelease) return autorelease; } +/* + * call-seq: ptr.autorelease? + * @return [Boolean] + * Get +autorelease+ attribute. See also Autorelease section. + */ static VALUE ptr_autorelease_p(VALUE self) { @@ -350,7 +429,19 @@ rbffi_Pointer_Init(VALUE moduleFFI) { VALUE rbNullAddress = ULL2NUM(0); + /* + * Document-class: FFI::Pointer + * Pointer class is used to manage C pointers with ease. A {Pointer} object is defined by his + * {#address} (as a C pointer). It permits additions with an integer for pointer arithmetic. + * + * ==Autorelease + * A pointer object may autorelease his contents when freed (by default). This behaviour may be + * changed with {#autorelease=} method. + */ rbffi_PointerClass = rb_define_class_under(moduleFFI, "Pointer", rbffi_AbstractMemoryClass); + /* + * Document-variable: Pointer + */ rb_global_variable(&rbffi_PointerClass); rb_define_alloc_func(rbffi_PointerClass, ptr_allocate); diff --git a/ext/ffi_c/Type.c b/ext/ffi_c/Type.c index 42b9eb7..d606ae9 100644 --- a/ext/ffi_c/Type.c +++ b/ext/ffi_c/Type.c @@ -51,6 +51,12 @@ type_allocate(VALUE klass) return obj; } +/* + * Document-method: initialize + * call-seq: initialize(value) + * @param [Fixnum,Type] value + * @return [self] + */ static VALUE type_initialize(VALUE self, VALUE value) { @@ -72,6 +78,11 @@ type_initialize(VALUE self, VALUE value) return self; } +/* + * call-seq: type.size + * @return [Fixnum] + * Return type's size, in bytes. + */ static VALUE type_size(VALUE self) { @@ -82,6 +93,10 @@ type_size(VALUE self) return INT2FIX(type->ffiType->size); } +/* + * call-seq: type.alignment + * @return [Fixnum] + */ static VALUE type_alignment(VALUE self) { @@ -92,6 +107,11 @@ type_alignment(VALUE self) return INT2FIX(type->ffiType->alignment); } +/* + * call-seq: type.inspect + * @return [String] + * Inspect {Type} object. + */ static VALUE type_inspect(VALUE self) { @@ -128,6 +148,11 @@ builtin_type_free(BuiltinType *type) xfree(type); } +/* + * call-seq: type.inspect + * @return [String] + * Inspect {Type::Builtin} object. + */ static VALUE builtin_type_inspect(VALUE self) { @@ -216,8 +241,18 @@ void rbffi_Type_Init(VALUE moduleFFI) { VALUE moduleNativeType; - VALUE classType = rbffi_TypeClass = rb_define_class_under(moduleFFI, "Type", rb_cObject); - + /* + * Document-class: FFI::Type + * This class manages C types. + * + * It embbed {FFI::Type::Builtin} objects as constants (for names, + * see {FFI::NativeType}). + */ + rbffi_TypeClass = rb_define_class_under(moduleFFI, "Type", rb_cObject); + + /* + * Document-constant: FFI::TypeDefs + */ rb_define_const(moduleFFI, "TypeDefs", typeMap = rb_hash_new()); rb_define_const(moduleFFI, "SizeTypes", sizeMap = rb_hash_new()); rb_global_variable(&typeMap); @@ -226,19 +261,62 @@ rbffi_Type_Init(VALUE moduleFFI) id_type_size = rb_intern("type_size"); id_size = rb_intern("size"); - + /* + * Document-class: FFI::Type::Builtin + * Class for Built-in types. + */ classBuiltinType = rb_define_class_under(rbffi_TypeClass, "Builtin", rbffi_TypeClass); + /* + * Document-module: FFI::NativeType + * This module defines constants for native (C) types. + * + * ==Native type constants + * Native types are defined by constants : + * * INT8, SCHAR, CHAR + * * UINT8, UCHAR + * * INT16, SHORT, SSHORT + * * UINT16, USHORT + * * INT32,, INT, SINT + * * UINT32, UINT + * * INT64, LONG_LONG, SLONG_LONG + * * UINT64, ULONG_LONG + * * LONG, SLONG + * * ULONG + * * FLOAT32, FLOAT + * * FLOAT64, DOUBLE + * * POINTER + * * CALLBACK + * * FUNCTION + * * CHAR_ARRAY + * * BOOL + * * STRING (immutable string, nul terminated) + * * STRUCT (struct-b-value param or result) + * * ARRAY (array type definition) + * * MAPPED (custom native type) + * For function return type only : + * * VOID + * For function argument type only : + * * BUFFER_IN + * * BUFFER_OUT + * * VARARGS (function takes a variable number of arguments) + * + * All these constants are exported to {FFI} module prefixed with "TYPE_". + * They are objets from {FFI::Type::Builtin} class. + */ moduleNativeType = rb_define_module_under(moduleFFI, "NativeType"); + /* + * Document-global: FFI::Type + */ rb_global_variable(&rbffi_TypeClass); rb_global_variable(&classBuiltinType); rb_global_variable(&moduleNativeType); - rb_define_alloc_func(classType, type_allocate); - rb_define_method(classType, "initialize", type_initialize, 1); - rb_define_method(classType, "size", type_size, 0); - rb_define_method(classType, "alignment", type_alignment, 0); - rb_define_method(classType, "inspect", type_inspect, 0); + rb_define_alloc_func(rbffi_TypeClass, type_allocate); + rb_define_method(rbffi_TypeClass, "initialize", type_initialize, 1); + rb_define_method(rbffi_TypeClass, "size", type_size, 0); + rb_define_method(rbffi_TypeClass, "alignment", type_alignment, 0); + rb_define_method(rbffi_TypeClass, "inspect", type_inspect, 0); // Make Type::Builtin non-allocatable rb_undef_method(CLASS_OF(classBuiltinType), "new"); @@ -250,16 +328,19 @@ rbffi_Type_Init(VALUE moduleFFI) // Define all the builtin types #define T(x, ffiType) do { \ VALUE t = Qnil; \ - rb_define_const(classType, #x, t = builtin_type_new(classBuiltinType, NATIVE_##x, ffiType, #x)); \ + rb_define_const(rbffi_TypeClass, #x, t = builtin_type_new(classBuiltinType, NATIVE_##x, ffiType, #x)); \ rb_define_const(moduleNativeType, #x, t); \ rb_define_const(moduleFFI, "TYPE_" #x, t); \ } while(0) #define A(old_type, new_type) do { \ - VALUE t = rb_const_get(classType, rb_intern(#old_type)); \ - rb_const_set(classType, rb_intern(#new_type), t); \ + VALUE t = rb_const_get(rbffi_TypeClass, rb_intern(#old_type)); \ + rb_const_set(rbffi_TypeClass, rb_intern(#new_type), t); \ } while(0) + /* + * Document-constant: FFI::Type::Builtin::VOID + */ T(VOID, &ffi_type_void); T(INT8, &ffi_type_sint8); A(INT8, SCHAR); diff --git a/ext/ffi_c/ffi.c b/ext/ffi_c/ffi.c index f8c955f..1b92818 100644 --- a/ext/ffi_c/ffi.c +++ b/ext/ffi_c/ffi.c @@ -50,6 +50,11 @@ static VALUE moduleFFI = Qnil; void Init_ffi_c(void) { + /* + * Document-module: FFI + * + * This module embbed type constants from {FFI::NativeType}. + */ rbffi_FFIModule = moduleFFI = rb_define_module("FFI"); rb_global_variable(&moduleFFI); diff --git a/lib/ffi/pointer.rb b/lib/ffi/pointer.rb index 352eb65..16d2ecc 100644 --- a/lib/ffi/pointer.rb +++ b/lib/ffi/pointer.rb @@ -24,10 +24,15 @@ module FFI SIZE = Platform::ADDRESS_SIZE / 8 # Return the size of a pointer on the current platform, in bytes + # @return [Numeric] def self.size SIZE end + # @param [nil,Numeric] len length of string to return + # @return [String] + # Read pointer's contents as a string, or the first +len+ bytes of the + # equivalent string if +len+ is not +nil+. def read_string(len=nil) if len get_bytes(0, len) @@ -36,24 +41,54 @@ module FFI end end + # @param [Numeric] len length of string to return + # @return [String] + # Read the first +len+ bytes of pointer's contents as a string. + # + # Same as: + # ptr.read_string(len) # with len not nil def read_string_length(len) get_bytes(0, len) end + # @return [String] + # Read pointer's contents as a string. + # + # Same as: + # ptr.read_string # with no len def read_string_to_null get_string(0) end + # @param [String] str string to write + # @param [Numeric] len length of string to return + # @return [self] + # Write +len+ first bytes of +str+ in pointer's contents. + # + # Same as: + # ptr.write_string(str, len) # with len not nil def write_string_length(str, len) put_bytes(0, str, 0, len) end + # @param [String] str string to write + # @param [Numeric] len length of string to return + # @return [self] + # Write +str+ in pointer's contents, or first +len+ bytes if + # +len+ is not +nil+. def write_string(str, len=nil) len = str.bytesize unless len # Write the string data without NUL termination put_bytes(0, str, 0, len) end + # @param [Type] type type of data to read from pointer's contents + # @param [Symbol] reader method to send to +self+ to read +type+ + # @param [Numeric] length + # @return [Array] + # Read an array of +type+ of length +length+. + # @example + # ptr.write_array_of_type(TYPE_UINT8, :get_uint8, 4) # -> [1, 2, 3, 4] def read_array_of_type(type, reader, length) ary = [] size = FFI.type_size(type) @@ -65,6 +100,13 @@ module FFI ary end + # @param [Type] type type of data to write to pointer's contents + # @param [Symbol] writer method to send to +self+ to write +type+ + # @param [Array] ary + # @return [self] + # Write +ary+ in pointer's contents as +type+. + # @example + # ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4]) def write_array_of_type(type, writer, ary) size = FFI.type_size(type) tmp = self diff --git a/lib/ffi/types.rb b/lib/ffi/types.rb index cd94722..e721ba6 100644 --- a/lib/ffi/types.rb +++ b/lib/ffi/types.rb @@ -17,17 +17,29 @@ # version 3 along with this work. If not, see <http://www.gnu.org/licenses/>. # +# see {file:README} module FFI + # @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type} + # @param [Symbol] add new type definition's name to add + # @return [Type] + # Add a definition type to type definitions. def self.typedef(old, add) TypeDefs[add] = self.find_type(old) end + # (see FFI.typedef) def self.add_typedef(old, add) typedef old, add end + # @param [Type, DataConverter, Symbol] name + # @param [Hash] type_map if nil, {FFI::TypeDefs} is used + # @return [Type] + # Find a type in +type_map+ ({FFI::TypeDefs}, by default) from + # a type objet, a type name (symbol). If +name+ is a {DataConverter}, + # a new {Type::Mapped} is created. def self.find_type(name, type_map = nil) if name.is_a?(Type) name @@ -46,6 +58,7 @@ module FFI end end + # List of type definitions TypeDefs.merge!({ # The C void type; only useful for function return types :void => Type::VOID, @@ -120,11 +133,15 @@ module FFI :varargs => Type::VARARGS, }) - # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed + class StrPtrConverter extend DataConverter native_type Type::POINTER + # @param [Pointer] val + # @param [] ctx + # @return [Array<String, Pointer>] + # Returns a [ String, Pointer ] tuple so the C memory for the string can be freed def self.from_native(val, ctx) [ val.null? ? nil : val.get_string(0), val ] end @@ -133,6 +150,9 @@ module FFI typedef(StrPtrConverter, :strptr) + # @param type +type+ is an instance of class accepted by {FFI.find_type} + # @return [Numeric] + # Get +type+ size, in bytes. def self.type_size(type) find_type(type).size end |