Tag


with closure

Encode URI

local c = require'CBOR'
local TAG_URI = 32

c.coders['function'] = function (buffer, fct)
    fct(buffer)
end

local function URI (str)
    return function (buffer)
        c.coders.tag(buffer, TAG_URI)
        c.coders.text_string(buffer, str)
    end
end

c.encode{homepage = URI'http://www.luarocks.org'}

Encode/Decode BASE64

local c = require 'CBOR'
local b64 = require 'base64'
local TAG_BASE64 = 34

c.coders['function'] = function (buffer, fct)
    fct(buffer)
end

local function BASE64 (str)
    return function (buffer)
        c.coders.tag(buffer, TAG_BASE64)
        c.coders.text_string(buffer, b64.encode(str))
    end
end

c.register_tag(TAG_BASE64, function (str)
    assert(type(str) == 'string', "invalid data item")
    return b64.decode(str)
end)

c.encode{'encoded_as_string', BASE64'encoded_base64'}

with table as object

Add a method tocbor into the class or the prototype.

local c = require'CBOR'
local TAG_COMPLEX = 42

local Cplx = {}
do
    Cplx.__index = Cplx

    function Cplx.new (re, im)
        local obj = {
            re = tonumber(re),
            im = im ~= nil and tonumber(im) or 0.0,
        }
        return setmetatable(obj, Cplx)
    end

    function Cplx:__tostring ()
        return '(' .. tostring(self.re) .. ', ' .. tostring(self.im) .. ')'
    end

    function Cplx:tocbor (buffer)
        buffer[#buffer+1] = c.TAG(TAG_COMPLEX)
        buffer[#buffer+1] = c.ARRAY(2)
        c.coders.number(buffer, self.re)
        c.coders.number(buffer, self.im)
    end
end

c.coders.table = function (buffer, obj)
    local mt = getmetatable(obj)
    if mt and mt.tocbor then
        obj:tocbor(buffer)
    else
        c.coders._table(buffer, obj)
    end
end

c.register_tag(TAG_COMPLEX, function (data)
    local re, im = unpack(data)
    return Cplx.new(re, im)
end)

local a = Cplx.new(1, 2)
c.encode(a)

With Coat, a method tocbor in each class is not needed.

local Meta = require 'Coat.Meta.Class'
local c = require 'CBOR'
local TAG_COAT = 1234

c.coders.table = function (buffer, obj)
    local classname = obj._CLASS
    if classname then
        buffer[#buffer+1] = c.TAG(TAG_COAT)
        buffer[#buffer+1] = c.ARRAY(2)
        c.coders.text_string(buffer, classname)
        c.coders._table(buffer, obj._VALUES)
    else
        c.coders._table(buffer, obj)
    end
end

c.register_tag(TAG_COAT, function (data)
    local classname, values = unpack(data)
    local class = assert(Meta.class(classname))
    return class.new(values)
end)
class 'Point'

has.x = { is = 'ro', isa = 'number', default = 0 }
has.y = { is = 'ro', isa = 'number', default = 0 }
has.desc = { is = 'rw', isa = 'string' }

function overload:__tostring ()
    return '(' .. tostring(self.x) .. ', ' .. tostring(self.y) .. ')'
end

local a = Point{x = 1, y = 2}
c.encode(a)

with userdata

local c = require'CBOR'
local bc = require 'bc'
local TAG_BC = 42
bc.digits(65)

c.coders.userdata = function (buffer, u)
    if getmetatable(u) == bc then
        c.coders.tag(buffer, TAG_BC)
        c.coders.text_string(buffer, tostring(u))
    else
        error("encode 'userdata' is unimplemented")
    end
end

c.register_tag(TAG_BC, function (data)
    return bc.number(data)
end)

With a method tocbor which contains the encoding stuff. This allows to work with many kind of userdata, CBOR.coders.userdata is generic.

local c = require'CBOR'
local bc = require 'bc'
local TAG_BC = 42
bc.digits(65)

function bc:tocbor (buffer)
    c.coders.tag(buffer, TAG_BC)
    c.coders.text_string(buffer, tostring(self))
end

c.coders.userdata = function (buffer, u)
    local mt = getmetatable(u)
    if mt and mt.tocbor then
        u:tocbor(buffer)
    else
        error("encode 'userdata' is unimplemented")
    end
end

c.register_tag(TAG_BC, function (data)
    return bc.number(data)
end)