beef331 / traitor

Trait/interface system for Nim, allowing semi-checked generics or dynamic dispatch on signatures.

Home Page:http://www.jasonbeetham.com/traitor/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Traitor

A macro heavy trait library made from bordem.

What does it do?!

Traitor allows one to use to use the new Nim concepts to describe interfaces that can ensure types implement procedures. It also enables runtime dispatch of procedures of those concepts.

The following is an example:

import traitor

type
  Clickable = concept
    proc over(a: Self, x, y: int): bool
    proc onClick(a: Self)

  Button = object
    x, y, w, h: int

  Radio {.byref.} = object # Objects smaller than 24 bytes need `{.byref.}`
    x, y, r: int

implTraits Clickable:
  proc over(btn: Button, x, y: int): bool =
    btn.x < x and (btn.x + btn.w) > x and btn.y < y and (btn.y + btn.h) > y

  proc onClick(btn: Button) =
    echo "Clicked a button"

  proc over(radio: Radio, x, y: int): bool =
    radio.r >= (abs(radio.x - x) + abs(radio.y - y))
  
  proc onClick(radio: Radio) = echo "Clicked a radio"

setupTraits Clickable # Implements the required logic for `Clickable` to be used

var
  elements = [
    Button(w: 10, h: 20).toImpl Clickable,
    Button(x: 30, y: 30, w: 10, h: 10), # Our converters enable this magic!
    Radio(x: 30, y: 30, r: 10)
  ]

assert elements[0].over(3, 3) # We can call procedures as if they're normal
assert elements[1].over(33, 33)
assert elements[2].over(30, 30)

for i, x in elements:
  if x of Button: # We can use `of` to check if it's the given type
    assert i in [0, 1]
  elif x of Radio:
    assert i == 2

assert (elements[2] as Radio) == Radio(x: 30, y: 30, r: 10) # We can use `as` to convert to a type
elements[2].to(Radio).x = 0 # We can also use `to` for chaining field access
assert elements[2].to(Radio).x == 0

By default traitor uses dynamically allocated buffers, if one wants to do fixed size buffers one can do -d:traitorBufferSize=YourSize and it'll use array[YourSize, byte] as a backer to hold the data. Alternatively one can use withTraitorBufferSize to temporaily change the buffer size. Though doing this will emit distinct objects that cannot be used homogenously with any other objects.

About

Trait/interface system for Nim, allowing semi-checked generics or dynamic dispatch on signatures.

http://www.jasonbeetham.com/traitor/


Languages

Language:Nim 100.0%