local ffi = require "ffi" local ffi_new = ffi.new local ffi_str = ffi.string local ffi_load = ffi.load local ffi_cdef = ffi.cdef local C = ffi.C local OSX = ffi.os == "OSX" local pcall = pcall local assert = assert local tonumber = tonumber local setmetatable = setmetatable ffi_cdef[[ typedef unsigned char uuid_t[16]; typedef long time_t; typedef struct timeval { time_t tv_sec; time_t tv_usec; } timeval; void uuid_generate(uuid_t out); void uuid_generate_random(uuid_t out); void uuid_generate_time(uuid_t out); int uuid_generate_time_safe(uuid_t out); int uuid_parse(const char *in, uuid_t uu); void uuid_unparse(const uuid_t uu, char *out); int uuid_type(const uuid_t uu); int uuid_variant(const uuid_t uu); time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); ]] local function L(n) local ok, lib = pcall(ffi_load, n) if ok then return lib end ok, lib = pcall(ffi_load, n .. '.so.1') assert(ok, lib) return lib end local lib = OSX and C or L "uuid" local uid = ffi_new "uuid_t" local tvl = ffi_new "timeval" local buf = ffi_new("char[?]", 36) local uuid = {} local mt = {} local function unparse(id) lib.uuid_unparse(id, buf) return ffi_str(buf, 36) end local function parse(id) return lib.uuid_parse(id, uid) == 0 and uid or nil end function uuid.generate() lib.uuid_generate(uid) return unparse(uid) end function uuid.generate_random() lib.uuid_generate_random(uid) return unparse(uid) end function uuid.generate_time() lib.uuid_generate_time(uid) return unparse(uid) end function uuid.generate_time_safe() assert(not OSX, "uuid_generate_time_safe is not supported on OS X.") local safe = lib.uuid_generate_time_safe(uid) == 0 return unparse(uid), safe end function uuid.type(id) assert(not OSX, "uuid_type is not supported on OS X.") local parsed = parse(id) return parsed and lib.uuid_type(parsed) end function uuid.variant(id) assert(not OSX, "uuid_variant is not supported on OS X.") local parsed = parse(id) return parsed and lib.uuid_variant(parsed) end function uuid.time(id) local parsed = parse(id) if parsed then local secs = lib.uuid_time(parsed, tvl) return tonumber(secs), tonumber(tvl.tv_usec) end end function uuid.is_valid(id) return not not parse(id) end mt.__call = uuid.generate return setmetatable(uuid, mt)