Created
December 15, 2014 12:25
-
-
Save gradha/a855001d1e878a07452b to your computer and use it in GitHub Desktop.
Source code for http://forum.nim-lang.org/t/673
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
######################### | |
# 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