
Research
/Security News
DuckDB npm Account Compromised in Continuing Supply Chain Attack
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
= ffi_dry
Helpers, sugar methods, and new features over Ruby FFI to do some common things and add support for some uncommon ones.
== Requirements
== Synopsis
(samples/ in the package for code)
A major feature is a DSL"-like" syntax for declaring structure members in FFI::Struct or FFI::ManagedStruct definitions.
require 'rubygems'
require 'ffi'
require 'ffi/dry'
class SomeStruct < FFI::Struct
include FFI::DRY::StructHelper
# we get a new way of specifying layouts with a 'dsl'-like syntax
# The hash containing {:desc => ... } can contain arbitrary keys which
# can be used however we like. dsl_metadata will contain all these
# in the class and instance.
dsl_layout do
field :field1, :uint16, :desc => 'this is field 1'
field :field2, :uint16, :desc => 'this is field 2'
end
end
ss0=SomeStruct.new
With the declarations above, we specified :desc hash value in metadata Let's check out in our instance.
pp ss0.dsl_metadata
[{:type=>:uint16, :name=>:field1, :desc=>"this is field 1"},
{:type=>:uint16, :name=>:field2, :desc=>"this is field 2"}]
# => nil
Or class.
pp SomeStruct.dsl_metadata
#...
We get some additional ways of instantiating and declaring values for free during initialization. (The FFI standard ways still work too)
raw_data = "\x00\x00\xff\xff"
ss1=SomeStruct.new :raw => raw_data
ss2=SomeStruct.new :raw => raw_data, :field1 => 1, :field2 => 2
ss3=SomeStruct.new {|x| x.field1=1 }
ss4=SomeStruct.new(:raw => raw_data) {|x| x.field1=1 }
[ ss0,
ss1,
ss2,
ss3,
ss4 ].each_with_index {|x,i| p ["ss#{i}",[x.field1, x.field2]]}
# which will produce...
# ["ss0", [0, 0]]
# ["ss1", [0, 65535]]
# ["ss2", [1, 2]]
# ["ss3", [1, 0]]
# ["ss4", [1, 65535]]
Here's a broader example which utilizes that arbitrary ':desc' parameter in a "neighborly" way. This also demonstrates superclasses to add common struct features, declaring array fields, as well as nesting other structs.
require 'rubygems'
require 'ffi'
require 'ffi/dry'
class NeighborlyStruct < ::FFI::Struct
include ::FFI::DRY::StructHelper
def self.describe
print "Struct: #{self.name}"
dsl_metadata().each_with_index do |spec, i|
print " Field #{i}\n"
print " name: #{spec[:name].inspect}\n"
print " type: #{spec[:type].inspect}\n"
print " desc: #{spec[:desc]}\n\n"
end
print "\n"
end
def describe; self.class.describe; end
end
class TestStruct < NeighborlyStruct
dsl_layout do
field :field1, :uint8, :desc => "test field 1"
field :field2, :uint8, :desc => "test field 2"
end
end
class SomeStruct < NeighborlyStruct
dsl_layout do
field :kind, :uint8, :desc => "a type identifier"
struct :tst, TestStruct, :desc => "a nested TestStruct"
field :len, :uint8, :desc => "8-bit size value (>= self.size+2)"
array :str, [:char,255],
:desc => "a string up to 255 bytes bound by :len"
end
# override kind getter method with our own
# resolves kind to some kind of type array for example...
def kind
[:default, :bar, :baz][ self[:kind] ]
end
end
s1=TestStruct.new
s2=SomeStruct.new
# check out that 'kind' override:
s2.kind
# => :default
# oh and the regular FFI way is always intact
s2[:kind]
# => 0
s2[:kind]=1
s2.kind
# => :bar
s2.kind=3
s2.kind
# => :baz
puts "*"*70
s1.describe
## we get a dump of metadata
# **********************************************************************
# Struct: TestStruct
# Field 0
# name: :field1
# type: :uint8
# desc: test field 1
#
# Field 1
# name: :field2
# type: :uint8
# desc: test field 2
puts "*"*70
s2.describe
## we get a dump of metadata
# Struct: SomeStruct Field 0
# name: :kind
# type: :uint8
# desc: a type identifier
#
# Field 1
# name: :tst
# type: TestStruct
# desc: a nested TestStruct
#
# Field 2
# name: :len
# type: :uint8
# desc: 8-bit size value (>= self.size+2)
#
# Field 3
# name: :str
# type: [:char, 255]
# desc: a string up to 255 bytes bound by :len
puts "*"*70
s2.tst.describe
## same as s1.describe
# **********************************************************************
# Struct: TestStruct
# Field 0
# name: :field1
# type: :uint8
# desc: test field 1
#
# Field 1
# name: :field2
# type: :uint8
# desc: test field 2
There's also some helpers for collecting lookup maps for constants, a common and handy thing when porting various libraries. We use Socket here just for example purposes, you can 'slurp' constants form any namespace this way.
require 'ffi/dry'
require 'socket'
module AddressFamily
include FFI::DRY::ConstMap
slurp_constants ::Socket, "AF_"
def list ; @@list ||= super() ; end # only generate the hash once
end
AddressFamily now has all the constants it found for Socket::AF_* minus the prefix.
AddressFamily::INET AddressFamily::LINK AddressFamily::INET6
etc...
We can do type or value lookups using []
AddressFamily[2] # => "INET"
AddressFamily["INET"] # => 2
We can get a hash of all constant->value pairs with .list
AddressFamily.list
# => {"NATM"=>31, "DLI"=>13, "UNIX"=>1, "NETBIOS"=>33, ...}
... and invert for a reverse mapping
AddressFamily.list.invert
# => {16=>"APPLETALK", 5=>"CHAOS", 27=>"NDRV", 0=>"UNSPEC", ...}
== License
Copyright (c) 2009 Eric Monti. See LICENSE for details.
FAQs
Unknown package
We found that emonti-ffi_dry demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Ongoing npm supply chain attack spreads to DuckDB: multiple packages compromised with the same wallet-drainer malware.
Security News
The MCP Steering Committee has launched the official MCP Registry in preview, a central hub for discovering and publishing MCP servers.
Product
Socket’s new Pull Request Stories give security teams clear visibility into dependency risks and outcomes across scanned pull requests.