class _FFI(Object) from 'ffi'
{
	method(#primitive) open(name).
	method(#primitive) close.
	method(#primitive) getsym(name).
	 
	(* TODO: make call variadic? method(#primitive,#variadic) call (func, sig). *)
	method(#primitive) call(func, sig, args).
}

class FFI(Object)
{
	var name, ffi, funcs.

	method(#class) new: aString
	{
		^self new open: aString.
	}

	method initialize 
	{
		self.funcs := Dictionary new.
		self.ffi := _FFI new.
	}

	method open: name
	{
		| x |
		self.funcs removeAllKeys.
		self.name := name.

		x := self.ffi open(name).
		(x isError) ifTrue: [^x].

		^self.
	}

	method close
	{
		self.ffi close.
	}

	method call: name signature: sig arguments: args
	{
		| f |
		f := self.funcs at: name.
		(f isError) ifTrue: [
			f := self.ffi getsym(name).
			(f isError) ifTrue: [^f].
			self.funcs at: name put: f.
		].

		^self.ffi call(f, sig, args)
	}
}
