clean up enum-based dispatch for Layouts, pulling in enum_dispatch crate.

This commit is contained in:
bunnie 2021-06-16 17:41:47 +08:00
parent 356b07dacc
commit 03bcf18348
4 changed files with 48 additions and 63 deletions

14
Cargo.lock generated
View file

@ -548,6 +548,18 @@ dependencies = [
"xous-names",
]
[[package]]
name = "enum_dispatch"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8"
dependencies = [
"once_cell",
"proc-macro2 1.0.24",
"quote 1.0.8",
"syn 1.0.60",
]
[[package]]
name = "env_logger"
version = "0.7.1"
@ -602,11 +614,11 @@ dependencies = [
name = "gam"
version = "0.1.0"
dependencies = [
"bitflags",
"blitstr-ref",
"chrono",
"com",
"content-plugin-api",
"enum_dispatch",
"graphics-server",
"heapless 0.7.0",
"ime-plugin-api",

View file

@ -6,12 +6,11 @@ name = "gam"
version = "0.1.0"
[dependencies]
bitflags = "1.2.1"
blitstr-ref = {path = "../../imports/blitstr-ref"}
com = {path = "../com"}
content-plugin-api = {path = "../content-plugin-api"}
graphics-server = {path = "../graphics-server"}
heapless = "0.7"
heapless = "0.7" # used for creating a sortable heap of canvas objects
ime-plugin-api = {path = "../ime-plugin-api"}
ime-plugin-shell = {path = "../ime-plugin-shell"}
keyboard = {path = "../keyboard"}
@ -29,6 +28,8 @@ num-derive = {version = "0.3", default-features = false}
num-traits = {version = "0.2", default-features = false}
rkyv = {version = "0.4.3", default-features = false, features = ["const_generics"]}
enum_dispatch = "0.3.7" # used for trait-based dispatch off of multiple layout objects.
[target.'cfg(not(any(windows,unix)))'.dependencies]
utralib = {path = "../../utralib"}

View file

@ -5,19 +5,7 @@ use blitstr_ref as blitstr;
use blitstr::GlyphStyle;
use graphics_server::*;
pub(crate) trait LayoutApi {
type Layout;
fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng,
base_trust: u8, status_canvas: &Canvas,
canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<Self::Layout, xous::Error>;
fn clear(&self, gfx: &graphics_server::Gfx, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<(), xous::Error>;
// for Chats, this resizes the height of the input area; for menus, it resizes the overall height
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<Point, xous::Error>;
fn get_input_canvas(&self) -> Option<Gid> { None }
fn get_prediction_canvas(&self) -> Option<Gid> { None }
fn get_content_canvas(&self) -> Gid; // layouts always have a content canvas
}
use crate::LayoutApi;
#[derive(Debug, Copy, Clone)]
// GIDs of canvases that are used the "Chat" layout.
@ -34,10 +22,9 @@ pub(crate) struct ChatLayout {
small_height: i16,
regular_height: i16,
}
impl LayoutApi for ChatLayout {
type Layout = ChatLayout;
impl ChatLayout {
// pass in the status canvas so we can size around it, but we can't draw on it
fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng, base_trust: u8,
pub fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng, base_trust: u8,
status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<ChatLayout, xous::Error> {
let screensize = gfx.screen_size().expect("Couldn't get screen size");
// get the height of various text regions to compute the layout
@ -77,6 +64,8 @@ impl LayoutApi for ChatLayout {
regular_height,
})
}
}
impl LayoutApi for ChatLayout {
fn clear(&self, gfx: &graphics_server::Gfx, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<(), xous::Error> {
let input_canvas = canvases.get(&self.input).expect("couldn't find input canvas");
let content_canvas = canvases.get(&self.content).expect("couldn't find content canvas");
@ -147,9 +136,8 @@ pub(crate) struct MenuLayout {
screensize: Point,
small_height: i16,
}
impl LayoutApi for MenuLayout {
type Layout = MenuLayout;
fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng, base_trust: u8, _status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<MenuLayout, xous::Error> {
impl MenuLayout {
pub fn init(gfx: &graphics_server::Gfx, trng: &trng::Trng, base_trust: u8, _status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<MenuLayout, xous::Error> {
let screensize = gfx.screen_size().expect("Couldn't get screen size");
// get the height of various text regions to compute the layout
let small_height: i16 = gfx.glyph_height_hint(GlyphStyle::Small).expect("couldn't get glyph height") as i16;
@ -172,6 +160,8 @@ impl LayoutApi for MenuLayout {
small_height,
})
}
}
impl LayoutApi for MenuLayout {
fn clear(&self, gfx: &graphics_server::Gfx, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<(), xous::Error> {
let menu_canvas = canvases.get(&self.menu).expect("couldn't find menu canvas");

View file

@ -27,46 +27,28 @@ use xous::{msg_scalar_unpack, msg_blocking_scalar_unpack};
use core::{sync::atomic::{AtomicU32, Ordering}};
use enum_dispatch::enum_dispatch;
//// todo:
// - create menu server
// - move vibe call to the GAM, reduce keyboard connections to 1
// - add auth tokens to audio streams, so less trusted processes can make direct connections to the codec and reduce latency
// - create menu server
// - macro-ize the unwrapping of the UxLayout enum
#[enum_dispatch]
pub(crate) trait LayoutApi {
fn clear(&self, gfx: &graphics_server::Gfx, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<(), xous::Error>;
// for Chats, this resizes the height of the input area; for menus, it resizes the overall height
fn resize_height(&mut self, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<Point, xous::Error>;
fn get_input_canvas(&self) -> Option<Gid> { None }
fn get_prediction_canvas(&self) -> Option<Gid> { None }
fn get_content_canvas(&self) -> Gid; // layouts always have a content canvas
}
#[enum_dispatch(LayoutApi)]
#[derive(Debug, Copy, Clone)]
pub(crate) enum UxLayout {
Chat(ChatLayout),
Menu(MenuLayout),
}
pub(crate) fn uxlayout_get_content_canvas(ul: UxLayout) -> Gid {
match ul {
UxLayout::Chat(layout) => layout.get_content_canvas(),
UxLayout::Menu(layout) => layout.get_content_canvas(),
}
}
pub(crate) fn uxlayout_resize_height(ul: &mut UxLayout, gfx: &graphics_server::Gfx, new_height: i16, status_canvas: &Canvas, canvases: &mut FnvIndexMap<Gid, Canvas, MAX_CANVASES>) -> Result<Point, xous::Error> {
match ul {
UxLayout::Chat(layout) => layout.resize_height(gfx, new_height, status_canvas, canvases),
UxLayout::Menu(layout) => layout.resize_height(gfx, new_height, status_canvas, canvases),
}
}
pub(crate) fn uxlayout_clear(ul: UxLayout, gfx: &graphics_server::Gfx, canvases: &mut FnvIndexMap<Gid, Canvas, {crate::MAX_CANVASES}>) -> Result<(), xous::Error> {
match ul {
UxLayout::Chat(layout) => layout.clear(gfx, canvases),
UxLayout::Menu(layout) => layout.clear(gfx, canvases),
}
}
pub(crate) fn uxlayout_get_input_canvas(ul: UxLayout) -> Option<Gid> {
match ul {
UxLayout::Chat(layout) => layout.get_input_canvas(),
UxLayout::Menu(layout) => layout.get_input_canvas(),
}
}
pub(crate) fn uxlayout_get_prediction_canvas(ul: UxLayout) -> Option<Gid> {
match ul {
UxLayout::Chat(layout) => layout.get_prediction_canvas(),
UxLayout::Menu(layout) => layout.get_prediction_canvas(),
}
ChatLayout,
MenuLayout,
}
#[derive(Debug, Copy, Clone)]
@ -136,7 +118,7 @@ impl ContextManager {
let chatlayout = ChatLayout::init(&gfx, &trng,
BOOT_CONTEXT_TRUSTLEVEL, &status_canvas, canvases).expect("couldn't create chat layout");
let ux_context = UxContext {
layout: UxLayout::Chat(chatlayout),
layout: UxLayout::ChatLayout(chatlayout),
predictor: registration.predictor,
app_token: token,
gam_token: [trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap(), ],
@ -159,7 +141,7 @@ impl ContextManager {
let menulayout = MenuLayout::init(&gfx, &trng,
BOOT_CONTEXT_TRUSTLEVEL, &status_canvas, canvases).expect("couldn't create menu layout");
let ux_context = UxContext {
layout: UxLayout::Menu(menulayout),
layout: UxLayout::MenuLayout(menulayout),
predictor: None,
app_token: token,
gam_token: [trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap(), trng.get_u32().unwrap(), ],
@ -196,7 +178,7 @@ impl ContextManager {
for maybe_context in self.contexts.iter() {
if let Some(context) = maybe_context {
if context.app_token == token {
return Some(uxlayout_get_content_canvas(context.layout));
return Some(context.layout.get_content_canvas());
}
}
}
@ -212,7 +194,7 @@ impl ContextManager {
for maybe_context in self.contexts.iter_mut() {
if let Some(context) = maybe_context {
if context.gam_token == gam_token {
let result = uxlayout_resize_height(&mut context.layout, gfx, new_height, status_canvas, canvases).expect("couldn't adjust height of active Ux context");
let result = context.layout.resize_height(gfx, new_height, status_canvas, canvases).expect("couldn't adjust height of active Ux context");
return Some(result)
}
}
@ -230,14 +212,14 @@ impl ContextManager {
if let Some(context) = maybe_context {
if context.app_token == token {
let descriptor = ImefDescriptor {
input_canvas: uxlayout_get_input_canvas(context.layout),
prediction_canvas: uxlayout_get_prediction_canvas(context.layout),
input_canvas: context.layout.get_input_canvas(),
prediction_canvas: context.layout.get_prediction_canvas(),
predictor: context.predictor,
token: context.gam_token,
};
imef.connect_backend(descriptor).expect("couldn't connect IMEF to the current app");
if clear {
uxlayout_clear(context.layout, gfx, canvases).expect("can't clear on context activation");
context.layout.clear(gfx, canvases).expect("can't clear on context activation");
}
// now update the IMEF area, since we're initialized
// note: we may need to skip this call if the context does not utilize a predictor...