Skip to content

Instantly share code, notes, and snippets.

@gradha
Created December 15, 2014 12:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gradha/a855001d1e878a07452b to your computer and use it in GitHub Desktop.
Save gradha/a855001d1e878a07452b to your computer and use it in GitHub Desktop.
#########################
# CODE INCLUDED BY BOTH
# COMPILATION UNITS.
# Trait definition
type DrawableVTable* = tuple[
drawType: int,
preDraw: proc(self: ref TObject): bool {.nimcall.},
draw: proc(self: ref TObject) {.nimcall.}
]
# Fat pointer: (object with type erased, pointer to v-table).
type
Drawable* = tuple[self: ref TObject, vtable: ptr DrawableVTable]
# Convenience functions for the trait.
proc drawType*(d: Drawable): int {.inline.} =
result = d.vtable.drawType
proc preDraw*(d: Drawable): bool {.inline.} =
result = d.vtable.preDraw(d.self)
proc draw*(d: Drawable) {.inline.} =
d.vtable.draw(d.self)
#########################
# COMPILATION UNIT 1
# (dynamic library)
# Main library with general-purpose drawObject
# function which uses all drawable types.
type
DrawingEngine* = object
objs : seq[Drawable]
# Function using trait.
proc drawObjects(engine: DrawingEngine) =
for obj in engine.objs:
echo("----")
if obj.preDraw():
echo("drawType = " & $obj.drawType)
obj.draw()
proc addDrawable*(engine: var DrawingEngine, obj: Drawable) =
engine.objs.add(obj)
# Global engine. Should also be exposed through a trait.
var engine = DrawingEngine(objs: @[])
#########################
# COMPILATION UNIT 2
# 3-party plugin
# (dynamic library)
import strutils
# Object implementing that trait
type Circle = object
x, y, r : float
proc preDrawC(self: ref TObject): bool {.procvar.} =
# Some data-ready check.
let circle = cast[ref Circle](self)
echo("Pre-draw for circle (x: $1, y: $2, r: $3)")
result = circle.r != 0
proc drawC(self: ref TObject) {.procvar.} =
let circle = cast[ref Circle](self)
echo(format("Drawing circle (x: $1, y: $2, r: $3)",
circle.x, circle.y, circle.r))
proc toDrawable(circle: ref Circle): Drawable =
# Global vtable for Circle's Drawable implementation.
var CircleVTable {.global.} = DrawableVTable((
drawType: 5,
preDraw: preDrawC,
draw: drawC))
result = (cast[ref TObject](circle), addr CircleVTable)
proc newCircle(x, y, r: float): ref Circle =
result.new
result.x = x
result.y = y
result.r = r
# The drawing engine would be exposed.
var circle1 = newCircle(0, 0, 1)
var circle2 = newCircle(0, 0, 0)
engine.addDrawable(circle1.toDrawable())
engine.addDrawable(circle2.toDrawable())
#########################
# This would be called eventually within the engine itself.
engine.drawObjects()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment