summaryrefslogtreecommitdiffstats
path: root/lua-bindings/src/lib.rs
blob: fcf307b310ad30cab77b7deadcd53af8ac295505 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::{sync::atomic::{AtomicUsize, Ordering}, cell::RefCell};

use diaphragm_cairo_renderer::CairoRenderer;
use diaphragm_core::{
    solving::VariableHandle,
    text::{FontDescription as CoreFontDescription, FontStyle, FontWeight, Text as CoreText},
    types::Float as CoreFloat,
    Runtime,
};
use diaphragm_z3_solver::{z3, Z3Context};
use mlua::prelude::*;

static MAX_ID: AtomicUsize = AtomicUsize::new(0);

thread_local! {
    static SENDER: RefCell<Option<Runtime<'static>>> = RefCell::new(None);
}

#[derive(Clone, Copy, Debug)]
struct Float(CoreFloat);

impl Float {
    fn new() -> Float {
        Float(CoreFloat::Variable(VariableHandle::new(
            MAX_ID.fetch_add(1, Ordering::SeqCst),
        )))
    }
}
impl LuaUserData for Float {}

fn float(_: &Lua, _: ()) -> LuaResult<Float> {
    Ok(Float::new())
}

#[derive(Clone, Debug)]
struct FontDescription(CoreFontDescription);
impl LuaUserData for FontDescription {}

const DEFAULT_FONT_FAMILY: &str = "serif";

impl Default for FontDescription {
    fn default() -> Self {
        Self(CoreFontDescription {
            family: DEFAULT_FONT_FAMILY.to_string(),
            style: FontStyle::Normal,
            weight: FontWeight::Normal,
            size: Float::new().0,
        })
    }
}

fn font(_: &Lua, params: LuaTable) -> LuaResult<FontDescription> {
    // TODO: better validation of the table
    // What happens when I mistype a param?
    // TODO: better error handling

    let family = params
        .get::<_, Option<_>>("family")?
        .unwrap_or_else(|| DEFAULT_FONT_FAMILY.to_string());

    let style = match params.get::<_, Option<String>>("style")?.as_deref() {
        Some("normal") | None => FontStyle::Normal,
        Some(_) => return Err(LuaError::RuntimeError("Unknown style".to_string())),
    };

    let weight = match params.get::<_, Option<String>>("weight")?.as_deref() {
        Some("normal") | None => FontWeight::Normal,
        Some(_) => return Err(LuaError::RuntimeError("Unknown weight".to_string())),
    };

    let size = params
        .get::<_, Option<_>>("size")?
        .unwrap_or_else(Float::new);

    Ok(FontDescription(CoreFontDescription {
        family,
        style,
        weight,
        size: size.0,
    }))
}

#[derive(Clone, Debug)]
struct Text(CoreText);
impl LuaUserData for Text {
    fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
        methods.add_method("draw", |_, this, _params: ()| {
            println!("I'm drawing: {}", this.0.content);
            Ok(())
        })
    }
}

fn text(_: &Lua, params: LuaTable) -> LuaResult<Text> {
    let content = params.get("content")?;

    let font = params
        .get::<_, Option<FontDescription>>("font")?
        .unwrap_or_default();

    Ok(Text(CoreText {
        content,
        font: font.0,
    }))
}

fn draw(_: &Lua, params: LuaTable) -> LuaResult<()> {
    let content: LuaTable = params.get("content")?;
    let output: LuaTable = params.get("output")?;

    let z3_cfg = z3::Config::new();
    let z3_ctx = z3::Context::new(&z3_cfg);
    let ctx = Z3Context::new(&z3_ctx);

    let cairo_renderer = CairoRenderer::new();

    // TODO: we shouldn't need the renderer until the end
    let mut runtime = Runtime::new(Box::new(ctx), Box::new(cairo_renderer));

    let _solver = runtime.solver_ctx();

    dbg!(content, output);

    Ok(())
}

#[mlua::lua_module]
fn libdiaphragm(lua: &Lua) -> LuaResult<LuaTable> {
    // TODO: the solver as a mutable global solves so much problem (pun not intended)
    let exports = lua.create_table()?;
    exports.set("text", lua.create_function(text)?)?;
    exports.set("font", lua.create_function(font)?)?;
    exports.set("float", lua.create_function(float)?)?;

    exports.set("draw", lua.create_function(draw)?)?;

    Ok(exports)
}