scheme support refactoring
This commit is contained in:
parent
01e0871111
commit
dfcc06fb31
|
@ -2,7 +2,7 @@ use std::{marker::PhantomData, mem, slice::ChunksExactMut};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum PixelFormat {
|
pub enum PixelFormat {
|
||||||
Argb8888Le,
|
Argb8888Le,
|
||||||
}
|
}
|
||||||
|
|
205
src/keyboard.rs
205
src/keyboard.rs
|
@ -1,12 +1,15 @@
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
graphics::{self, LazyCanvas},
|
graphics::{self, LazyCanvas},
|
||||||
image::PixelFormat,
|
image::PixelFormat,
|
||||||
script::{Engine, Value},
|
script::{Engine, Func, ValTrait, Value},
|
||||||
text::FontDb,
|
text::FontDb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod script;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Popup {
|
pub struct Popup {
|
||||||
left: i32,
|
left: i32,
|
||||||
top: i32,
|
top: i32,
|
||||||
|
@ -21,6 +24,7 @@ pub struct PopupInfo<'b> {
|
||||||
font_db: &'b mut FontDb,
|
font_db: &'b mut FontDb,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct Class<E: Engine> {
|
pub struct Class<E: Engine> {
|
||||||
pub supers: Vec<String>,
|
pub supers: Vec<String>,
|
||||||
pub methods: HashMap<String, E::Func>,
|
pub methods: HashMap<String, E::Func>,
|
||||||
|
@ -43,18 +47,24 @@ pub struct Keyboard<E: Engine> {
|
||||||
fmt: PixelFormat,
|
fmt: PixelFormat,
|
||||||
pub(crate) font_db: FontDb,
|
pub(crate) font_db: FontDb,
|
||||||
is_first_draw: bool,
|
is_first_draw: bool,
|
||||||
config_handlers: HashMap<
|
pub(crate) user_data: HashMap<String, Value<Self>>,
|
||||||
String,
|
pub(crate) classes: HashMap<String, Class<Self>>,
|
||||||
Vec<(
|
/// SAFETY: unsafe
|
||||||
usize,
|
engine: E,
|
||||||
Box<dyn 'static + FnMut(&Self, &str, &toml_edit::Value)>,
|
}
|
||||||
)>,
|
impl<E: Engine> Debug for Keyboard<E> {
|
||||||
>,
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
timers: Vec<(Instant, Box<dyn 'static + FnOnce(&Self)>)>,
|
f.debug_struct("Keyboard")
|
||||||
config_handler_id: usize,
|
.field("layout", &self.layout)
|
||||||
pub(crate) user_data: HashMap<String, Value<E>>,
|
.field("popup", &self.popup)
|
||||||
pub(crate) classes: HashMap<String, Class<E>>,
|
.field("width", &self.width)
|
||||||
pub(crate) env: Option<crate::ScriptEnv<E>>,
|
.field("height", &self.height)
|
||||||
|
.field("fmt", &self.fmt)
|
||||||
|
.field("font_db", &self.font_db)
|
||||||
|
.field("is_first_draw", &self.is_first_draw)
|
||||||
|
.field("classes", &self.classes)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> PopupInfo<'b> {
|
impl<'b> PopupInfo<'b> {
|
||||||
|
@ -127,15 +137,9 @@ pub struct DamageInfo {
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Default for Keyboard<E> {
|
impl<E: 'static + Engine> Keyboard<E> {
|
||||||
fn default() -> Self {
|
pub fn new(engine: E) -> Self {
|
||||||
Self::new()
|
let mut ret = Self {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: Engine> Keyboard<E> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
width: 720,
|
width: 720,
|
||||||
height: 480,
|
height: 480,
|
||||||
font_db: Default::default(),
|
font_db: Default::default(),
|
||||||
|
@ -143,16 +147,16 @@ impl<E: Engine> Keyboard<E> {
|
||||||
layout: None,
|
layout: None,
|
||||||
popup: None,
|
popup: None,
|
||||||
is_first_draw: true,
|
is_first_draw: true,
|
||||||
config_handlers: HashMap::new(),
|
|
||||||
config_handler_id: 0,
|
|
||||||
timers: Vec::new(),
|
|
||||||
user_data: HashMap::new(),
|
user_data: HashMap::new(),
|
||||||
classes: HashMap::new(),
|
classes: HashMap::new(),
|
||||||
env: None,
|
engine,
|
||||||
}
|
};
|
||||||
|
script::init_builtins(&mut ret);
|
||||||
// ret.layout = Some(ret.create_layout());
|
// ret.layout = Some(ret.create_layout());
|
||||||
// ret
|
ret
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
impl<E: Engine> Keyboard<E> {
|
||||||
pub fn size(&self) -> (u32, u32) {
|
pub fn size(&self) -> (u32, u32) {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
@ -189,24 +193,6 @@ impl<E: Engine> Keyboard<E> {
|
||||||
is_first_draw: true,
|
is_first_draw: true,
|
||||||
});*/
|
});*/
|
||||||
}
|
}
|
||||||
pub fn _add_settings_handler(
|
|
||||||
&mut self,
|
|
||||||
key: &str,
|
|
||||||
handler: impl 'static + FnMut(&Self, &str, &toml_edit::Value),
|
|
||||||
) -> usize {
|
|
||||||
let id = self.config_handler_id;
|
|
||||||
self.config_handler_id += 1;
|
|
||||||
self.config_handlers
|
|
||||||
.entry(key.to_owned())
|
|
||||||
.or_default()
|
|
||||||
.push((id, Box::new(handler)));
|
|
||||||
id
|
|
||||||
}
|
|
||||||
pub fn _remove_settings_handler(&mut self, key: &str, id: usize) {
|
|
||||||
if let Some(x) = self.config_handlers.get_mut(key) {
|
|
||||||
x.retain(|(i, _)| id != *i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn hide(&mut self) {
|
pub fn hide(&mut self) {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
|
@ -235,10 +221,7 @@ impl<E: Engine> Keyboard<E> {
|
||||||
.and_then(|cls| cls.methods.get_mut("kbd/width-changed"))
|
.and_then(|cls| cls.methods.get_mut("kbd/width-changed"))
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let mut env = self.env.take().unwrap();
|
func.call(self, vec![Value::Symbol("en".into())]).unwrap();
|
||||||
env.call(self, &func, vec![Value::Symbol("en".into())])
|
|
||||||
.unwrap();
|
|
||||||
self.env = Some(env);
|
|
||||||
}
|
}
|
||||||
self.is_first_draw = false;
|
self.is_first_draw = false;
|
||||||
if let Some(layout) = &mut self.layout {
|
if let Some(layout) = &mut self.layout {
|
||||||
|
@ -361,3 +344,123 @@ impl<E: Engine> Keyboard<E> {
|
||||||
layout
|
layout
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct ValueWrapper<E: Engine>(E::Value);
|
||||||
|
impl<E: Engine> ValTrait for ValueWrapper<E> {
|
||||||
|
type Engine = Keyboard<E>;
|
||||||
|
fn from_val2(val: Value<Self::Engine>, engine: &mut Self::Engine) -> Self {
|
||||||
|
Self(E::Value::from_val2(val.convert(), &mut engine.engine))
|
||||||
|
}
|
||||||
|
fn from_val(val: Value<Self::Engine>) -> Self {
|
||||||
|
Self(E::Value::from_val(val.convert()))
|
||||||
|
}
|
||||||
|
fn to_val(&self) -> Value<Self::Engine> {
|
||||||
|
self.0.to_val().convert()
|
||||||
|
}
|
||||||
|
fn to_val2(&self, engine: &Self::Engine) -> Value<Self::Engine> {
|
||||||
|
self.0.to_val2(&engine.engine).convert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FuncWrapper<E: Engine>(E::Func);
|
||||||
|
impl<E: Engine> Clone for FuncWrapper<E>
|
||||||
|
where
|
||||||
|
E::Func: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self(self.0.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Engine> Ord for FuncWrapper<E>
|
||||||
|
where
|
||||||
|
E::Func: Ord,
|
||||||
|
{
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.0.cmp(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Engine> Eq for FuncWrapper<E> where E::Func: Eq {}
|
||||||
|
impl<E: Engine> PartialOrd for FuncWrapper<E>
|
||||||
|
where
|
||||||
|
E::Func: PartialOrd,
|
||||||
|
{
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.0.cmp(&other.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Engine> PartialEq for FuncWrapper<E>
|
||||||
|
where
|
||||||
|
E::Func: PartialEq,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.0.eq(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<E: Engine> Func for FuncWrapper<E> {
|
||||||
|
type BasicValue = <E::Func as Func>::BasicValue;
|
||||||
|
fn from_basic_value(v: Self::BasicValue) -> Self {
|
||||||
|
Self(E::Func::from_basic_value(v))
|
||||||
|
}
|
||||||
|
fn into_basic_value(self) -> Self::BasicValue {
|
||||||
|
self.0.into_basic_value()
|
||||||
|
}
|
||||||
|
type Engine = Keyboard<E>;
|
||||||
|
fn call(
|
||||||
|
&self,
|
||||||
|
engine: &mut Self::Engine,
|
||||||
|
args: Vec<Value<Self::Engine>>,
|
||||||
|
) -> Result<Value<Self::Engine>, <Self::Engine as Engine>::Error> {
|
||||||
|
Ok(self
|
||||||
|
.0
|
||||||
|
.call(
|
||||||
|
&mut engine.engine,
|
||||||
|
args.into_iter().map(Value::convert).collect(),
|
||||||
|
)?
|
||||||
|
.convert())
|
||||||
|
}
|
||||||
|
fn unref(&mut self, engine: &mut Self::Engine) {
|
||||||
|
self.0.unref(&mut engine.engine);
|
||||||
|
}
|
||||||
|
fn add_ref(&mut self, engine: &mut Self::Engine) {
|
||||||
|
self.0.add_ref(&mut engine.engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> Engine for Keyboard<E> {
|
||||||
|
type Value = ValueWrapper<E>;
|
||||||
|
type Error = E::Error;
|
||||||
|
type Func = FuncWrapper<E>;
|
||||||
|
fn eval_t(&mut self, text: &str) -> Result<Value<Self>, Self::Error> {
|
||||||
|
Ok(self.engine.eval_t(text)?.convert())
|
||||||
|
}
|
||||||
|
fn gc(&mut self) {
|
||||||
|
self.engine.gc();
|
||||||
|
}
|
||||||
|
fn register(&mut self, name: &str, val: Value<Self>) {
|
||||||
|
self.engine.register(name, val.convert())
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn register_func(
|
||||||
|
&mut self,
|
||||||
|
name: &'static str,
|
||||||
|
func: impl 'static + Fn(&mut Self, Vec<Value<Self>>) -> Result<Value<Self>, Self::Error>,
|
||||||
|
) {
|
||||||
|
self.engine.register_func(name, move |a: &mut E, b| {
|
||||||
|
Ok(func(
|
||||||
|
// SAFETY: as long as engine isn't used directly by the Keyboard,
|
||||||
|
// and self is used as the engine itself, this is fine
|
||||||
|
unsafe {
|
||||||
|
let ofs = std::mem::offset_of!(Self, engine);
|
||||||
|
let ptr: *mut Self = ((a as *mut E) as *mut Self).byte_sub(ofs);
|
||||||
|
&mut *ptr
|
||||||
|
},
|
||||||
|
// SAFETY: should have the same layout,
|
||||||
|
// because FuncWrapper is repr(transparent)
|
||||||
|
unsafe { std::mem::transmute::<Vec<Value<E>>, Vec<Value<Self>>>(b) },
|
||||||
|
)?
|
||||||
|
.convert())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
469
src/keyboard/script.rs
Normal file
469
src/keyboard/script.rs
Normal file
|
@ -0,0 +1,469 @@
|
||||||
|
use crate::{
|
||||||
|
graphics, image,
|
||||||
|
script::{Args, Engine, ErrorTrait, Func, Value},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Keyboard;
|
||||||
|
|
||||||
|
fn register<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 3], _>([cls, name, func]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/register"));
|
||||||
|
};
|
||||||
|
let Value::Symbol(cls) = cls else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/register",
|
||||||
|
"symbol",
|
||||||
|
&format!("{cls:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::Symbol(name) = name else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/register",
|
||||||
|
"symbol",
|
||||||
|
&format!("{name:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::Func(mut func) = func else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/register",
|
||||||
|
"function",
|
||||||
|
&format!("{func:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
func.add_ref(vm);
|
||||||
|
println!("register {cls:?} {name:?} {func:?}");
|
||||||
|
vm.classes
|
||||||
|
.entry(cls.into_owned())
|
||||||
|
.or_default()
|
||||||
|
.methods
|
||||||
|
.insert(name.into_owned(), func);
|
||||||
|
println!("done");
|
||||||
|
|
||||||
|
Ok(Value::Null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_define<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 2], _>([cls, supers]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/class-define"));
|
||||||
|
};
|
||||||
|
let Value::Symbol(cls) = cls else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/class-define",
|
||||||
|
"symbol",
|
||||||
|
&format!("{cls:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let supers = match supers {
|
||||||
|
Value::Null => vec![],
|
||||||
|
Value::RevArray(supers) => supers,
|
||||||
|
_ => {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/class-define",
|
||||||
|
"list",
|
||||||
|
&format!("{supers:?}"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let supers = supers
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.map(|sup| {
|
||||||
|
let Value::Symbol(sup) = sup else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/class-define",
|
||||||
|
"list of symbols",
|
||||||
|
&format!("list containing {sup:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
Ok(sup.into_owned())
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
println!("register {cls:?} {supers:?}");
|
||||||
|
|
||||||
|
vm.classes
|
||||||
|
.entry(cls.into_owned())
|
||||||
|
.or_default()
|
||||||
|
.supers
|
||||||
|
.extend(supers);
|
||||||
|
println!("done");
|
||||||
|
Ok(Value::Null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
mut args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
args.reverse();
|
||||||
|
let cls = args
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| ErrorTrait::invalid_argc("kbd/call"))?;
|
||||||
|
let name = args
|
||||||
|
.pop()
|
||||||
|
.ok_or_else(|| ErrorTrait::invalid_argc("kbd/call"))?;
|
||||||
|
let Value::Symbol(cls) = cls else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/call",
|
||||||
|
"symbol",
|
||||||
|
&format!("{cls:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::Symbol(name) = name else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/call",
|
||||||
|
"symbol",
|
||||||
|
&format!("{name:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
fn call_func<E: Engine>(
|
||||||
|
func: &mut E::Func,
|
||||||
|
engine: &mut E,
|
||||||
|
args: Vec<Value<E>>,
|
||||||
|
) -> Result<Value<E>, E::Error> {
|
||||||
|
func.call(engine, args)
|
||||||
|
}
|
||||||
|
let func = vm
|
||||||
|
.classes
|
||||||
|
.get_mut(cls.as_ref())
|
||||||
|
.and_then(|cls| cls.methods.get_mut(name.as_ref()).cloned());
|
||||||
|
if let Some(mut func) = func {
|
||||||
|
args.push(Value::Symbol(cls));
|
||||||
|
args.reverse();
|
||||||
|
call_func(&mut func, vm, args)
|
||||||
|
} else {
|
||||||
|
Err(ErrorTrait::from_str(
|
||||||
|
"kbd/call",
|
||||||
|
&format!("{cls}/{name} is not defined"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_user_data<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 2], _>([k, mut v]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/set-user-data"));
|
||||||
|
};
|
||||||
|
let Value::Symbol(k) = k else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/set-user-data",
|
||||||
|
"symbol",
|
||||||
|
&format!("{k:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
println!("setting user data {k:?} to {v:?}");
|
||||||
|
if let Some(mut val) = vm.user_data.insert(k.into_owned(), v.clone()) {
|
||||||
|
// FIXME: theoretically this can unref data that's referenced elsewhere
|
||||||
|
val.unref(vm);
|
||||||
|
}
|
||||||
|
v.add_ref(vm);
|
||||||
|
Ok(Value::Null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_user_data<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 1], _>([k]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/get-user-data"));
|
||||||
|
};
|
||||||
|
let Value::Symbol(k) = k else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/get-user-data",
|
||||||
|
"symbol",
|
||||||
|
&format!("{k:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
println!("getting user data {k:?}");
|
||||||
|
Ok(vm
|
||||||
|
.user_data
|
||||||
|
.get(k.as_ref())
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Value::Bool(false)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_i64<E: Engine>(name: &str, a: Value<E>, b: Value<E>) -> Result<i64, E::Error> {
|
||||||
|
Ok(match (a, b) {
|
||||||
|
(Value::Int(a), Value::Int(b)) => a.saturating_add(b),
|
||||||
|
(Value::Float(a), Value::Float(b)) => (a + b) as i64,
|
||||||
|
(Value::Int(a), Value::Float(b)) => (a as f64 + b) as i64,
|
||||||
|
(Value::Float(a), Value::Int(b)) => (a + b as f64) as i64,
|
||||||
|
x => {
|
||||||
|
return Err(E::Error::invalid_argt(
|
||||||
|
name,
|
||||||
|
"int or float",
|
||||||
|
&format!("{:?}", x.1),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn to_i64<E: Engine>(name: &str, x: Value<E>) -> Result<i64, E::Error> {
|
||||||
|
add_to_i64(name, x, Value::Int(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_text<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 5], _>([xy, wh, text, font, font_size]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/make-text"));
|
||||||
|
};
|
||||||
|
let Value::Pair(xy) = xy else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-text",
|
||||||
|
"pair",
|
||||||
|
&format!("{xy:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::Pair(wh) = wh else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-text",
|
||||||
|
"pair",
|
||||||
|
&format!("{wh:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::String(text) = text else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-text",
|
||||||
|
"string",
|
||||||
|
&format!("{text:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::String(font) = font else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-text",
|
||||||
|
"string",
|
||||||
|
&format!("{font:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let font_size = match font_size {
|
||||||
|
Value::Int(x) => x as f64,
|
||||||
|
Value::Float(x) => x,
|
||||||
|
_ => {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-text",
|
||||||
|
"string",
|
||||||
|
&format!("{font_size:?}"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let Some(font_handle) = vm.font_db.font_handle(&font) else {
|
||||||
|
return Err(ErrorTrait::from_str("kbd/make-text", "font not found"));
|
||||||
|
};
|
||||||
|
let (x, y) = *xy;
|
||||||
|
let (w, h) = *wh;
|
||||||
|
let x1 = to_i64("kbd/make-text", x.clone())?;
|
||||||
|
let y1 = to_i64("kbd/make-text", y.clone())?;
|
||||||
|
let x_w = add_to_i64("kbd/make-text", x, w)?;
|
||||||
|
let y_h = add_to_i64("kbd/make-text", y, h)?;
|
||||||
|
let (x, y) = (x1, y1);
|
||||||
|
let (w, h) = (x_w - x, y_h - y);
|
||||||
|
let halign = graphics::Alignment::Middle;
|
||||||
|
let valign = graphics::Alignment::Middle;
|
||||||
|
let direction = swash::shape::Direction::LeftToRight;
|
||||||
|
let script = swash::text::Script::Latin;
|
||||||
|
let color = image::ColorRgba([255, 0, 0, 255]);
|
||||||
|
// [xy, wh, text, font, font_size]
|
||||||
|
// println!("rendering text {text} of size {w}/{h} at {x}/{y} with font {font} {font_size}, color {color:?}, alignment {halign:?}/{valign:?}, script {script:?}, direction {direction:?}");
|
||||||
|
let text = graphics::WidgetEnum::Text(graphics::Text {
|
||||||
|
direction,
|
||||||
|
font_size: font_size as f32,
|
||||||
|
font_handle,
|
||||||
|
color,
|
||||||
|
halign,
|
||||||
|
valign,
|
||||||
|
script,
|
||||||
|
text: text.into(),
|
||||||
|
pos: graphics::Rect {
|
||||||
|
left: x as i32,
|
||||||
|
bottom: y as i32,
|
||||||
|
height: h as u32,
|
||||||
|
width: w as u32,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Value::from_serde(&text).map_err(|err| ErrorTrait::from_str("kbd/make-text", &err.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_rect<E: Engine>(
|
||||||
|
_vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let mut args = args.into_iter();
|
||||||
|
let Some(xy) = args.next() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/make-rect"));
|
||||||
|
};
|
||||||
|
let Some(wh) = args.next() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/make-rect"));
|
||||||
|
};
|
||||||
|
let mut round = 0.0f64;
|
||||||
|
while let Some(arg) = args.next() {
|
||||||
|
match arg {
|
||||||
|
Value::Symbol(x) if x == ":round-corners" => {
|
||||||
|
round = 1.0;
|
||||||
|
if let Some(arg) = args.next() {
|
||||||
|
let Value::Float(arg) = arg else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-rect",
|
||||||
|
"float",
|
||||||
|
&format!("{arg:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
round = arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-rect",
|
||||||
|
"make-rect keyword arguments",
|
||||||
|
&format!("{x:?}"),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Value::Pair(xy) = xy else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-rect",
|
||||||
|
"pair",
|
||||||
|
&format!("{xy:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Value::Pair(wh) = wh else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-rect",
|
||||||
|
"pair",
|
||||||
|
&format!("{wh:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let (x, y) = *xy;
|
||||||
|
let (w, h) = *wh;
|
||||||
|
let x1 = to_i64("kbd/make-rect", x.clone())?;
|
||||||
|
let y1 = to_i64("kbd/make-rect", y.clone())?;
|
||||||
|
let x_w = add_to_i64("kbd/make-rect", x, w)?;
|
||||||
|
let y_h = add_to_i64("kbd/make-rect", y, h)?;
|
||||||
|
let (x, y) = (x1, y1);
|
||||||
|
let (w, h) = (x_w - x, y_h - y);
|
||||||
|
let color = image::ColorRgba([0, 0, 0, 255]);
|
||||||
|
// [xy, wh, text, font, font_size]
|
||||||
|
println!("rendering rect of size {w}/{h} at {x}/{y} with rounding {round}, color {color:?}");
|
||||||
|
let rect = graphics::WidgetEnum::Shape(graphics::SimpleShape {
|
||||||
|
col: color,
|
||||||
|
pos: graphics::Rect {
|
||||||
|
left: x as i32,
|
||||||
|
bottom: y as i32,
|
||||||
|
width: w as u32,
|
||||||
|
height: h as u32,
|
||||||
|
},
|
||||||
|
round_corners_ratio: round as f32,
|
||||||
|
});
|
||||||
|
Value::from_serde(&rect).map_err(|err| ErrorTrait::from_str("kbd/make-rect", &err.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_layout<E: Engine>(
|
||||||
|
_vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 1], _>([items]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/make-layout"));
|
||||||
|
};
|
||||||
|
let Value::RevArray(items) = items else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-layout",
|
||||||
|
"list",
|
||||||
|
&format!("{items:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let mut layout = graphics::Layout::new();
|
||||||
|
for item in items.into_iter().rev() {
|
||||||
|
let Value::RevArray(mut item) = item else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/make-layout",
|
||||||
|
"list of lists",
|
||||||
|
&format!("list with {item:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Some(Value::String(a)) = item.pop() else {
|
||||||
|
return Err(ErrorTrait::from_str(
|
||||||
|
"kbd/make-layout",
|
||||||
|
"each item's first element must be the item id",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let item = Value::RevArray(item)
|
||||||
|
.to_serde()
|
||||||
|
.map_err(|err| ErrorTrait::from_str("kbd/make-layout", &err.to_string()))?;
|
||||||
|
// println!("{item:#?}");
|
||||||
|
layout.add_child(item, &a, None);
|
||||||
|
}
|
||||||
|
Value::from_serde(&layout)
|
||||||
|
.map_err(|err| ErrorTrait::from_str("kbd/make-layout", &err.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn width<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 0], _>([]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/width"));
|
||||||
|
};
|
||||||
|
println!("getting keyboard width");
|
||||||
|
Ok(Value::Int(vm.width.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_font<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 1], _>([path]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/load-font"));
|
||||||
|
};
|
||||||
|
let Value::String(path) = path else {
|
||||||
|
return Err(ErrorTrait::invalid_argt(
|
||||||
|
"kbd/load-font",
|
||||||
|
"string",
|
||||||
|
&format!("{path:?}"),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
println!("loading font {path:?}");
|
||||||
|
vm.font_db
|
||||||
|
.load_font(path)
|
||||||
|
.map(|()| Value::Null)
|
||||||
|
.map_err(|err| ErrorTrait::from_str("kbd/load-font", &err.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_layout<E: Engine>(
|
||||||
|
vm: &mut Keyboard<E>,
|
||||||
|
args: Args<Keyboard<E>>,
|
||||||
|
) -> Result<Value<Keyboard<E>>, <Keyboard<E> as Engine>::Error> {
|
||||||
|
let Ok::<[Value<_>; 1], _>([layout]) = args.try_into() else {
|
||||||
|
return Err(ErrorTrait::invalid_argc("kbd/set-layout"));
|
||||||
|
};
|
||||||
|
let layout: graphics::Layout = layout
|
||||||
|
.to_serde()
|
||||||
|
.map_err(|err| ErrorTrait::from_str("kbd/set-layout", &err.to_string()))?;
|
||||||
|
vm.layout = Some(layout);
|
||||||
|
Ok(Value::Null)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_builtins<E: 'static + Engine>(engine: &mut Keyboard<E>) {
|
||||||
|
const DEFS: &str = include_str!("../../defs.scm");
|
||||||
|
engine.eval_t(DEFS).unwrap();
|
||||||
|
engine.gc();
|
||||||
|
engine.register_func("kbd/register", register);
|
||||||
|
engine.register_func("kbd/class-define", class_define);
|
||||||
|
engine.register_func("kbd/call", call);
|
||||||
|
engine.register_func("kbd/set-user-data", set_user_data);
|
||||||
|
engine.register_func("kbd/get-user-data", get_user_data);
|
||||||
|
engine.register_func("kbd/make-text", make_text);
|
||||||
|
engine.register(":round-corners", Value::new_symbol(":round-corners"));
|
||||||
|
engine.register_func("kbd/make-rect", make_rect);
|
||||||
|
engine.register_func("kbd/make-layout", make_layout);
|
||||||
|
engine.register_func("kbd/width", width);
|
||||||
|
engine.register_func("kbd/load-font", load_font);
|
||||||
|
engine.register_func("kbd/set-layout", set_layout);
|
||||||
|
engine.gc();
|
||||||
|
}
|
506
src/main.rs
506
src/main.rs
|
@ -1,7 +1,6 @@
|
||||||
#![allow(clippy::type_complexity)]
|
#![allow(clippy::type_complexity)]
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
|
|
||||||
use script::{Engine, ErrorTrait, Func, Value};
|
use script::Engine;
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
pub use wayland_protocols_misc;
|
pub use wayland_protocols_misc;
|
||||||
|
|
||||||
|
@ -17,509 +16,12 @@ mod text;
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
mod wayland;
|
mod wayland;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ScriptEnv<E: Engine>(E, Rc<RefCell<Keyboard<E>>>);
|
|
||||||
|
|
||||||
impl<E: Engine> ScriptEnv<E> {
|
|
||||||
fn eval(&mut self, kbd: &mut Keyboard<E>, text: &str) -> Result<Value<E>, E::Error> {
|
|
||||||
std::mem::swap(kbd, &mut (*self.1).borrow_mut());
|
|
||||||
let ret = self.0.eval_t(text);
|
|
||||||
std::mem::swap(kbd, &mut (*self.1).borrow_mut());
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
fn call(
|
|
||||||
&mut self,
|
|
||||||
kbd: &mut Keyboard<E>,
|
|
||||||
func: &E::Func,
|
|
||||||
args: Vec<Value<E>>,
|
|
||||||
) -> Result<Value<E>, E::Error> {
|
|
||||||
std::mem::swap(kbd, &mut (*self.1).borrow_mut());
|
|
||||||
// work with kbd1
|
|
||||||
let ret = func.call(&mut self.0, args);
|
|
||||||
std::mem::swap(kbd, &mut (*self.1).borrow_mut());
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_script_env() -> ScriptEnv<impl Engine> {
|
|
||||||
let mut engine = script::create_engine();
|
|
||||||
const DEFS: &str = include_str!("../defs.scm");
|
|
||||||
let ctx: Rc<RefCell<Keyboard<_>>> = Rc::default();
|
|
||||||
engine.eval_t(DEFS).unwrap();
|
|
||||||
engine.gc();
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/register",
|
|
||||||
Box::new(move |vm, args| {
|
|
||||||
let Ok::<[Value<_>; 3], _>([cls, name, func]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/register"));
|
|
||||||
};
|
|
||||||
let Value::Symbol(cls) = cls else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/register",
|
|
||||||
"symbol",
|
|
||||||
&format!("{cls:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::Symbol(name) = name else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/register",
|
|
||||||
"symbol",
|
|
||||||
&format!("{name:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::Func(mut func) = func else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/register",
|
|
||||||
"function",
|
|
||||||
&format!("{func:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
func.add_ref(vm);
|
|
||||||
println!("register {cls:?} {name:?} {func:?}");
|
|
||||||
(*ctx1)
|
|
||||||
.borrow_mut()
|
|
||||||
.classes
|
|
||||||
.entry(cls.into_owned())
|
|
||||||
.or_default()
|
|
||||||
.methods
|
|
||||||
.insert(name.into_owned(), func);
|
|
||||||
println!("done");
|
|
||||||
|
|
||||||
Ok(Value::Null)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/class-define",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 2], _>([cls, supers]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/class-define"));
|
|
||||||
};
|
|
||||||
let Value::Symbol(cls) = cls else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/class-define",
|
|
||||||
"symbol",
|
|
||||||
&format!("{cls:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let supers = match supers {
|
|
||||||
Value::Null => vec![],
|
|
||||||
Value::RevArray(supers) => supers,
|
|
||||||
_ => {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/class-define",
|
|
||||||
"list",
|
|
||||||
&format!("{supers:?}"),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let supers = supers
|
|
||||||
.into_iter()
|
|
||||||
.rev()
|
|
||||||
.map(|sup| {
|
|
||||||
let Value::Symbol(sup) = sup else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/class-define",
|
|
||||||
"list of symbols",
|
|
||||||
&format!("list containing {sup:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
Ok(sup.into_owned())
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
println!("register {cls:?} {supers:?}");
|
|
||||||
|
|
||||||
(*ctx1)
|
|
||||||
.borrow_mut()
|
|
||||||
.classes
|
|
||||||
.entry(cls.into_owned())
|
|
||||||
.or_default()
|
|
||||||
.supers
|
|
||||||
.extend(supers);
|
|
||||||
println!("done");
|
|
||||||
Ok(Value::Null)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/call",
|
|
||||||
Box::new(move |vm, mut args| {
|
|
||||||
args.reverse();
|
|
||||||
let cls = args
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| ErrorTrait::invalid_argc("kbd/call"))?;
|
|
||||||
let name = args
|
|
||||||
.pop()
|
|
||||||
.ok_or_else(|| ErrorTrait::invalid_argc("kbd/call"))?;
|
|
||||||
let Value::Symbol(cls) = cls else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/call",
|
|
||||||
"symbol",
|
|
||||||
&format!("{cls:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::Symbol(name) = name else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/call",
|
|
||||||
"symbol",
|
|
||||||
&format!("{name:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
fn call_func<E: Engine>(
|
|
||||||
func: &mut E::Func,
|
|
||||||
engine: &mut E,
|
|
||||||
args: Vec<Value<E>>,
|
|
||||||
) -> Result<Value<E>, E::Error> {
|
|
||||||
func.call(engine, args)
|
|
||||||
}
|
|
||||||
let func = (*ctx1)
|
|
||||||
.borrow_mut()
|
|
||||||
.classes
|
|
||||||
.get_mut(cls.as_ref())
|
|
||||||
.and_then(|cls| cls.methods.get_mut(name.as_ref()).cloned());
|
|
||||||
if let Some(mut func) = func {
|
|
||||||
args.push(Value::Symbol(cls));
|
|
||||||
args.reverse();
|
|
||||||
call_func(&mut func, vm, args)
|
|
||||||
} else {
|
|
||||||
Err(ErrorTrait::from_str(
|
|
||||||
"kbd/call",
|
|
||||||
&format!("{cls}/{name} is not defined"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/set-user-data",
|
|
||||||
Box::new(move |vm, args| {
|
|
||||||
let Ok::<[Value<_>; 2], _>([k, mut v]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/set-user-data"));
|
|
||||||
};
|
|
||||||
let Value::Symbol(k) = k else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/set-user-data",
|
|
||||||
"symbol",
|
|
||||||
&format!("{k:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
println!("setting user data {k:?} to {v:?}");
|
|
||||||
if let Some(mut val) = (*ctx1)
|
|
||||||
.borrow_mut()
|
|
||||||
.user_data
|
|
||||||
.insert(k.into_owned(), v.clone())
|
|
||||||
{
|
|
||||||
// FIXME: theoretically this can unref data that's referenced elsewhere
|
|
||||||
val.unref(vm);
|
|
||||||
}
|
|
||||||
v.add_ref(vm);
|
|
||||||
Ok(Value::Null)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/get-user-data",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 1], _>([k]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/get-user-data"));
|
|
||||||
};
|
|
||||||
let Value::Symbol(k) = k else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/get-user-data",
|
|
||||||
"symbol",
|
|
||||||
&format!("{k:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
println!("getting user data {k:?}");
|
|
||||||
Ok((*ctx1)
|
|
||||||
.borrow()
|
|
||||||
.user_data
|
|
||||||
.get(k.as_ref())
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or(Value::Bool(false)))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
fn add_to_i64<E: Engine>(name: &str, a: Value<E>, b: Value<E>) -> Result<i64, E::Error> {
|
|
||||||
Ok(match (a, b) {
|
|
||||||
(Value::Int(a), Value::Int(b)) => a.saturating_add(b),
|
|
||||||
(Value::Float(a), Value::Float(b)) => (a + b) as i64,
|
|
||||||
(Value::Int(a), Value::Float(b)) => (a as f64 + b) as i64,
|
|
||||||
(Value::Float(a), Value::Int(b)) => (a + b as f64) as i64,
|
|
||||||
x => {
|
|
||||||
return Err(E::Error::invalid_argt(
|
|
||||||
name,
|
|
||||||
"int or float",
|
|
||||||
&format!("{:?}", x.1),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn to_i64<E: Engine>(name: &str, x: Value<E>) -> Result<i64, E::Error> {
|
|
||||||
add_to_i64(name, x, Value::Int(0))
|
|
||||||
}
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/make-text",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 5], _>([xy, wh, text, font, font_size]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/make-text"));
|
|
||||||
};
|
|
||||||
let Value::Pair(xy) = xy else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-text",
|
|
||||||
"pair",
|
|
||||||
&format!("{xy:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::Pair(wh) = wh else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-text",
|
|
||||||
"pair",
|
|
||||||
&format!("{wh:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::String(text) = text else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-text",
|
|
||||||
"string",
|
|
||||||
&format!("{text:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::String(font) = font else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-text",
|
|
||||||
"string",
|
|
||||||
&format!("{font:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let font_size = match font_size {
|
|
||||||
Value::Int(x) => x as f64,
|
|
||||||
Value::Float(x) => x,
|
|
||||||
_ => {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-text",
|
|
||||||
"string",
|
|
||||||
&format!("{font_size:?}"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let Some(font_handle) = ctx1.borrow_mut().font_db.font_handle(&font) else {
|
|
||||||
return Err(ErrorTrait::from_str("kbd/make-text", "font not found"));
|
|
||||||
};
|
|
||||||
let (x, y) = *xy;
|
|
||||||
let (w, h) = *wh;
|
|
||||||
let x1 = to_i64("kbd/make-text", x.clone())?;
|
|
||||||
let y1 = to_i64("kbd/make-text", y.clone())?;
|
|
||||||
let x_w = add_to_i64("kbd/make-text", x, w)?;
|
|
||||||
let y_h = add_to_i64("kbd/make-text", y, h)?;
|
|
||||||
let (x, y) = (x1, y1);
|
|
||||||
let (w, h) = (x_w - x, y_h - y);
|
|
||||||
let halign = graphics::Alignment::Middle;
|
|
||||||
let valign = graphics::Alignment::Middle;
|
|
||||||
let direction = swash::shape::Direction::LeftToRight;
|
|
||||||
let script = swash::text::Script::Latin;
|
|
||||||
let color = image::ColorRgba([255, 0, 0, 255]);
|
|
||||||
// [xy, wh, text, font, font_size]
|
|
||||||
// println!("rendering text {text} of size {w}/{h} at {x}/{y} with font {font} {font_size}, color {color:?}, alignment {halign:?}/{valign:?}, script {script:?}, direction {direction:?}");
|
|
||||||
let text = graphics::WidgetEnum::Text(graphics::Text {
|
|
||||||
direction,
|
|
||||||
font_size: font_size as f32,
|
|
||||||
font_handle,
|
|
||||||
color,
|
|
||||||
halign,
|
|
||||||
valign,
|
|
||||||
script,
|
|
||||||
text: text.into(),
|
|
||||||
pos: graphics::Rect {
|
|
||||||
left: x as i32,
|
|
||||||
bottom: y as i32,
|
|
||||||
height: h as u32,
|
|
||||||
width: w as u32,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
Value::from_serde(&text)
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/make-text", &err.to_string()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
engine.register(":round-corners", Value::new_symbol(":round-corners"));
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/make-rect",
|
|
||||||
Box::new(|_vm, args| {
|
|
||||||
let mut args = args.into_iter();
|
|
||||||
let Some(xy) = args.next() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/make-rect"));
|
|
||||||
};
|
|
||||||
let Some(wh) = args.next() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/make-rect"));
|
|
||||||
};
|
|
||||||
let mut round = 0.0f64;
|
|
||||||
while let Some(arg) = args.next() {
|
|
||||||
match arg {
|
|
||||||
Value::Symbol(x) if x == ":round-corners" => {
|
|
||||||
round = 1.0;
|
|
||||||
if let Some(arg) = args.next() {
|
|
||||||
let Value::Float(arg) = arg else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-rect",
|
|
||||||
"float",
|
|
||||||
&format!("{arg:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
round = arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-rect",
|
|
||||||
"make-rect keyword arguments",
|
|
||||||
&format!("{x:?}"),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let Value::Pair(xy) = xy else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-rect",
|
|
||||||
"pair",
|
|
||||||
&format!("{xy:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Value::Pair(wh) = wh else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-rect",
|
|
||||||
"pair",
|
|
||||||
&format!("{wh:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let (x, y) = *xy;
|
|
||||||
let (w, h) = *wh;
|
|
||||||
let x1 = to_i64("kbd/make-rect", x.clone())?;
|
|
||||||
let y1 = to_i64("kbd/make-rect", y.clone())?;
|
|
||||||
let x_w = add_to_i64("kbd/make-rect", x, w)?;
|
|
||||||
let y_h = add_to_i64("kbd/make-rect", y, h)?;
|
|
||||||
let (x, y) = (x1, y1);
|
|
||||||
let (w, h) = (x_w - x, y_h - y);
|
|
||||||
let color = image::ColorRgba([0, 0, 0, 255]);
|
|
||||||
// [xy, wh, text, font, font_size]
|
|
||||||
println!(
|
|
||||||
"rendering rect of size {w}/{h} at {x}/{y} with rounding {round}, color {color:?}"
|
|
||||||
);
|
|
||||||
let rect = graphics::WidgetEnum::Shape(graphics::SimpleShape {
|
|
||||||
col: color,
|
|
||||||
pos: graphics::Rect {
|
|
||||||
left: x as i32,
|
|
||||||
bottom: y as i32,
|
|
||||||
width: w as u32,
|
|
||||||
height: h as u32,
|
|
||||||
},
|
|
||||||
round_corners_ratio: round as f32,
|
|
||||||
});
|
|
||||||
Value::from_serde(&rect)
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/make-rect", &err.to_string()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/make-layout",
|
|
||||||
Box::new(|_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 1], _>([items]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/make-layout"));
|
|
||||||
};
|
|
||||||
let Value::RevArray(items) = items else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-layout",
|
|
||||||
"list",
|
|
||||||
&format!("{items:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let mut layout = graphics::Layout::new();
|
|
||||||
for item in items.into_iter().rev() {
|
|
||||||
let Value::RevArray(mut item) = item else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/make-layout",
|
|
||||||
"list of lists",
|
|
||||||
&format!("list with {item:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let Some(Value::String(a)) = item.pop() else {
|
|
||||||
return Err(ErrorTrait::from_str(
|
|
||||||
"kbd/make-layout",
|
|
||||||
"each item's first element must be the item id",
|
|
||||||
));
|
|
||||||
};
|
|
||||||
let item = Value::RevArray(item)
|
|
||||||
.to_serde()
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/make-layout", &err.to_string()))?;
|
|
||||||
// println!("{item:#?}");
|
|
||||||
layout.add_child(item, &a, None);
|
|
||||||
}
|
|
||||||
Value::from_serde(&layout)
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/make-layout", &err.to_string()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/width",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 0], _>([]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/width"));
|
|
||||||
};
|
|
||||||
println!("getting keyboard width");
|
|
||||||
Ok(Value::Int(ctx1.borrow().width.into()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/load-font",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 1], _>([path]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/load-font"));
|
|
||||||
};
|
|
||||||
let Value::String(path) = path else {
|
|
||||||
return Err(ErrorTrait::invalid_argt(
|
|
||||||
"kbd/load-font",
|
|
||||||
"string",
|
|
||||||
&format!("{path:?}"),
|
|
||||||
));
|
|
||||||
};
|
|
||||||
println!("loading font {path:?}");
|
|
||||||
(*ctx1)
|
|
||||||
.borrow_mut()
|
|
||||||
.font_db
|
|
||||||
.load_font(path)
|
|
||||||
.map(|()| Value::Null)
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/load-font", &err.to_string()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
let ctx1 = ctx.clone();
|
|
||||||
engine.register_func(
|
|
||||||
"kbd/set-layout",
|
|
||||||
Box::new(move |_vm, args| {
|
|
||||||
let Ok::<[Value<_>; 1], _>([layout]) = args.try_into() else {
|
|
||||||
return Err(ErrorTrait::invalid_argc("kbd/set-layout"));
|
|
||||||
};
|
|
||||||
let layout: graphics::Layout = layout
|
|
||||||
.to_serde()
|
|
||||||
.map_err(|err| ErrorTrait::from_str("kbd/set-layout", &err.to_string()))?;
|
|
||||||
(*ctx1).borrow_mut().layout = Some(layout);
|
|
||||||
Ok(Value::Null)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
engine.gc();
|
|
||||||
ScriptEnv(engine, ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_type<T>(_: &T, _: &T) {}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let mut env = new_script_env();
|
let engine = script::create_engine();
|
||||||
// engine.gc();
|
let mut kbd: Keyboard<_> = Keyboard::new(engine);
|
||||||
let s = std::fs::read_to_string("tmp.scm").unwrap();
|
let s = std::fs::read_to_string("tmp.scm").unwrap();
|
||||||
let mut kbd = Keyboard::new();
|
kbd.eval_t(&s).unwrap();
|
||||||
assert_type(&kbd, &(*env.1.borrow()));
|
|
||||||
env.eval(&mut kbd, &s).unwrap();
|
|
||||||
kbd.env = Some(env);
|
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
if std::env::var_os("WAYLAND_DISPLAY").is_some() {
|
if std::env::var_os("WAYLAND_DISPLAY").is_some() {
|
||||||
|
|
|
@ -42,6 +42,22 @@ impl<E: Engine> Clone for Value<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Engine> Value<E> {
|
impl<E: Engine> Value<E> {
|
||||||
|
pub fn convert<R: Engine>(self) -> Value<R>
|
||||||
|
where
|
||||||
|
R::Func: Func<BasicValue = <E::Func as Func>::BasicValue>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Null => Value::Null,
|
||||||
|
Self::Bool(x) => Value::Bool(x),
|
||||||
|
Self::Int(x) => Value::Int(x),
|
||||||
|
Self::Float(x) => Value::Float(x),
|
||||||
|
Self::String(x) => Value::String(x),
|
||||||
|
Self::Symbol(x) => Value::Symbol(x),
|
||||||
|
Self::RevArray(x) => Value::RevArray(x.into_iter().map(Self::convert).collect()),
|
||||||
|
Self::Pair(x) => Value::new_pair(x.0.convert(), x.1.convert()),
|
||||||
|
Self::Func(x) => Value::Func(x.convert::<R>()),
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn new_symbol(s: impl Into<Cow<'static, str>>) -> Self {
|
pub fn new_symbol(s: impl Into<Cow<'static, str>>) -> Self {
|
||||||
Self::Symbol(s.into())
|
Self::Symbol(s.into())
|
||||||
}
|
}
|
||||||
|
@ -168,24 +184,16 @@ impl<E: Engine> Hash for Value<E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToVal {
|
|
||||||
type Engine: Engine;
|
|
||||||
fn to_val2(&self, _engine: &Self::Engine) -> Value<Self::Engine> {
|
|
||||||
self.to_val()
|
|
||||||
}
|
|
||||||
fn to_val(&self) -> Value<Self::Engine> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ErrorTrait {
|
pub trait ErrorTrait {
|
||||||
fn from_str(name: &str, s: &str) -> Self;
|
fn from_str(name: &str, s: &str) -> Self;
|
||||||
fn invalid_argc(name: &str) -> Self;
|
fn invalid_argc(name: &str) -> Self;
|
||||||
fn invalid_argt(name: &str, exp: &str, found: &str) -> Self;
|
fn invalid_argt(name: &str, exp: &str, found: &str) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Args<E> = Vec<Value<E>>;
|
||||||
|
|
||||||
pub trait Engine: Debug + Sized {
|
pub trait Engine: Debug + Sized {
|
||||||
type Value: FromVal<Engine = Self> + ToVal<Engine = Self>;
|
type Value: ValTrait<Engine = Self>;
|
||||||
type Error: Debug + ErrorTrait;
|
type Error: Debug + ErrorTrait;
|
||||||
type Func: Clone + Debug + Ord + Func<Engine = Self>;
|
type Func: Clone + Debug + Ord + Func<Engine = Self>;
|
||||||
fn eval_t(&mut self, text: &str) -> Result<Value<Self>, Self::Error>;
|
fn eval_t(&mut self, text: &str) -> Result<Value<Self>, Self::Error>;
|
||||||
|
@ -194,32 +202,40 @@ pub trait Engine: Debug + Sized {
|
||||||
// this doesnt have to be box, but it being a box saves some binary size
|
// this doesnt have to be box, but it being a box saves some binary size
|
||||||
fn new_func(
|
fn new_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
_name: &'static str,
|
||||||
func: Box<
|
_func: Box<dyn 'static + Fn(&mut Self, Args<Self>) -> Result<Value<Self>, Self::Error>>,
|
||||||
dyn 'static + Fn(&mut Self, Vec<Value<Self>>) -> Result<Value<Self>, Self::Error>,
|
) -> Self::Func {
|
||||||
>,
|
unimplemented!()
|
||||||
) -> Self::Func;
|
}
|
||||||
|
#[inline(always)]
|
||||||
fn register_func(
|
fn register_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
func: Box<
|
func: impl 'static + Fn(&mut Self, Args<Self>) -> Result<Value<Self>, Self::Error>,
|
||||||
dyn 'static + Fn(&mut Self, Vec<Value<Self>>) -> Result<Value<Self>, Self::Error>,
|
|
||||||
>,
|
|
||||||
) {
|
) {
|
||||||
let func = self.new_func(name, func);
|
let func = self.new_func(name, Box::new(func));
|
||||||
self.register(name, Value::Func(func));
|
self.register(name, Value::Func(func));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Func {
|
pub trait Func: Sized {
|
||||||
type Engine: Engine;
|
type Engine: Engine;
|
||||||
|
type BasicValue;
|
||||||
fn call(
|
fn call(
|
||||||
&self,
|
&self,
|
||||||
engine: &mut Self::Engine,
|
engine: &mut Self::Engine,
|
||||||
args: Vec<Value<Self::Engine>>,
|
args: Args<Self::Engine>,
|
||||||
) -> Result<Value<Self::Engine>, <Self::Engine as Engine>::Error>;
|
) -> Result<Value<Self::Engine>, <Self::Engine as Engine>::Error>;
|
||||||
fn add_ref(&mut self, engine: &mut Self::Engine);
|
fn add_ref(&mut self, engine: &mut Self::Engine);
|
||||||
fn unref(&mut self, engine: &mut Self::Engine);
|
fn unref(&mut self, engine: &mut Self::Engine);
|
||||||
|
fn from_basic_value(v: Self::BasicValue) -> Self;
|
||||||
|
fn into_basic_value(self) -> Self::BasicValue;
|
||||||
|
fn convert<R: Engine>(self) -> R::Func
|
||||||
|
where
|
||||||
|
R::Func: Func<BasicValue = Self::BasicValue>,
|
||||||
|
{
|
||||||
|
R::Func::from_basic_value(self.into_basic_value())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -288,10 +304,17 @@ impl PartialOrd for MarwoodFunc {
|
||||||
|
|
||||||
impl Func for MarwoodFunc {
|
impl Func for MarwoodFunc {
|
||||||
type Engine = marwood::vm::Vm;
|
type Engine = marwood::vm::Vm;
|
||||||
|
type BasicValue = Self;
|
||||||
|
fn into_basic_value(self) -> Self::BasicValue {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn from_basic_value(v: Self::BasicValue) -> Self {
|
||||||
|
v
|
||||||
|
}
|
||||||
fn call(
|
fn call(
|
||||||
&self,
|
&self,
|
||||||
engine: &mut Self::Engine,
|
engine: &mut Self::Engine,
|
||||||
args: Vec<Value<Self::Engine>>,
|
args: Args<Self::Engine>,
|
||||||
) -> Result<Value<Self::Engine>, <Self::Engine as Engine>::Error> {
|
) -> Result<Value<Self::Engine>, <Self::Engine as Engine>::Error> {
|
||||||
use marwood::vm::{lambda::Lambda, opcode::OpCode, vcell::VCell};
|
use marwood::vm::{lambda::Lambda, opcode::OpCode, vcell::VCell};
|
||||||
let (lambda, is_cont) = match self {
|
let (lambda, is_cont) = match self {
|
||||||
|
@ -437,15 +460,13 @@ impl Engine for marwood::vm::Vm {
|
||||||
fn register(&mut self, name: &str, val: Value<Self>) {
|
fn register(&mut self, name: &str, val: Value<Self>) {
|
||||||
let symbol = self.heap.put(marwood::vm::vcell::VCell::symbol(name));
|
let symbol = self.heap.put(marwood::vm::vcell::VCell::symbol(name));
|
||||||
let slot = self.globenv.get_binding(symbol.as_ptr().unwrap());
|
let slot = self.globenv.get_binding(symbol.as_ptr().unwrap());
|
||||||
let val = FromVal::from_val2(val, self);
|
let val = ValTrait::from_val2(val, self);
|
||||||
self.globenv.put_slot(slot, val);
|
self.globenv.put_slot(slot, val);
|
||||||
}
|
}
|
||||||
fn new_func(
|
fn new_func(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
func: Box<
|
func: Box<dyn 'static + Fn(&mut Self, Args<Self>) -> Result<Value<Self>, Self::Error>>,
|
||||||
dyn 'static + Fn(&mut Self, Vec<Value<Self>>) -> Result<Value<Self>, Self::Error>,
|
|
||||||
>,
|
|
||||||
) -> Self::Func {
|
) -> Self::Func {
|
||||||
let func = marwood::vm::vcell::VCell::builtin(name, move |vm| {
|
let func = marwood::vm::vcell::VCell::builtin(name, move |vm| {
|
||||||
// log::info!("calling {name}");
|
// log::info!("calling {name}");
|
||||||
|
@ -457,7 +478,7 @@ impl Engine for marwood::vm::Vm {
|
||||||
args.reverse();
|
args.reverse();
|
||||||
// log::info!("calling! {name}");
|
// log::info!("calling! {name}");
|
||||||
match func(vm, args) {
|
match func(vm, args) {
|
||||||
Ok(x) => Ok(FromVal::from_val2(x, vm)),
|
Ok(x) => Ok(ValTrait::from_val2(x, vm)),
|
||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
// log::info!("exiting {name}");
|
// log::info!("exiting {name}");
|
||||||
|
@ -472,8 +493,14 @@ impl Engine for marwood::vm::Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FromVal: Sized {
|
pub trait ValTrait: Sized {
|
||||||
type Engine: Engine;
|
type Engine: Engine;
|
||||||
|
fn to_val2(&self, _engine: &Self::Engine) -> Value<Self::Engine> {
|
||||||
|
self.to_val()
|
||||||
|
}
|
||||||
|
fn to_val(&self) -> Value<Self::Engine> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
fn from_val(_val: Value<Self::Engine>) -> Self {
|
fn from_val(_val: Value<Self::Engine>) -> Self {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -483,7 +510,7 @@ pub trait FromVal: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "steel")]
|
#[cfg(feature = "steel")]
|
||||||
impl FromVal for steel::SteelVal {
|
impl ValTrait for steel::SteelVal {
|
||||||
type Engine = steel::steel_vm::engine::Engine;
|
type Engine = steel::steel_vm::engine::Engine;
|
||||||
fn from_val(val: Value) -> Self {
|
fn from_val(val: Value) -> Self {
|
||||||
match val {
|
match val {
|
||||||
|
@ -512,7 +539,7 @@ impl FromVal for steel::SteelVal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromVal for marwood::vm::vcell::VCell {
|
impl ValTrait for marwood::vm::vcell::VCell {
|
||||||
type Engine = marwood::vm::Vm;
|
type Engine = marwood::vm::Vm;
|
||||||
fn from_val2(val: Value<Self::Engine>, engine: &mut Self::Engine) -> Self {
|
fn from_val2(val: Value<Self::Engine>, engine: &mut Self::Engine) -> Self {
|
||||||
match val {
|
match val {
|
||||||
|
@ -568,10 +595,6 @@ impl FromVal for marwood::vm::vcell::VCell {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl ToVal for marwood::vm::vcell::VCell {
|
|
||||||
type Engine = marwood::vm::Vm;
|
|
||||||
fn to_val2(&self, engine: &Self::Engine) -> Value<Self::Engine> {
|
fn to_val2(&self, engine: &Self::Engine) -> Value<Self::Engine> {
|
||||||
match self {
|
match self {
|
||||||
Self::Bool(val) => Value::Bool(*val),
|
Self::Bool(val) => Value::Bool(*val),
|
||||||
|
|
13
src/text.rs
13
src/text.rs
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
fmt::Debug,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
io,
|
io,
|
||||||
path::Path,
|
path::Path,
|
||||||
|
@ -22,11 +23,6 @@ impl CacheKey {
|
||||||
static KEY: AtomicU64 = AtomicU64::new(1);
|
static KEY: AtomicU64 = AtomicU64::new(1);
|
||||||
Self(KEY.fetch_add(1, Ordering::Relaxed))
|
Self(KEY.fetch_add(1, Ordering::Relaxed))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying value of the key.
|
|
||||||
pub fn value(self) -> u64 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for CacheKey {
|
impl Default for CacheKey {
|
||||||
|
@ -69,6 +65,13 @@ pub struct FontDb {
|
||||||
fonts: HashMap<String, FontHandle>,
|
fonts: HashMap<String, FontHandle>,
|
||||||
glyph_cache: HashMap<GlyphCacheKey, (Instant, Option<Image>)>,
|
glyph_cache: HashMap<GlyphCacheKey, (Instant, Option<Image>)>,
|
||||||
}
|
}
|
||||||
|
impl Debug for FontDb {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("FontDb")
|
||||||
|
.field("fonts", &self.fonts)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FontDb {
|
impl FontDb {
|
||||||
pub fn load_font(&mut self, file: impl AsRef<Path>) -> io::Result<()> {
|
pub fn load_font(&mut self, file: impl AsRef<Path>) -> io::Result<()> {
|
||||||
|
|
Loading…
Reference in a new issue