From 70c25f35827c8412acf076e81c2035f4e2c5b570 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Sat, 10 Dec 2022 00:57:24 +0100 Subject: [PATCH] [WIP] RUST: Implementing the safe interface over the unsafe C types and functions --- src/rust/liblektor-rs/Cargo.toml | 2 +- .../liblektor-rs/lektor_c_compat/Cargo.toml | 1 + .../lektor_c_compat/src/c_types.rs | 126 +++++++++++++++++- .../liblektor-rs/lektor_c_compat/src/lib.rs | 2 +- .../lektor_c_compat/src/rs_types.rs | 83 +++++++++++- src/rust/liblektor-rs/lektor_db/diesel.toml | 2 +- .../2022-09-30-204512_initial/up.sql | 2 +- .../lektor_db/src/database/schema.rs | 86 ------------ 8 files changed, 202 insertions(+), 102 deletions(-) delete mode 100644 src/rust/liblektor-rs/lektor_db/src/database/schema.rs diff --git a/src/rust/liblektor-rs/Cargo.toml b/src/rust/liblektor-rs/Cargo.toml index 01f109d3..6246c107 100644 --- a/src/rust/liblektor-rs/Cargo.toml +++ b/src/rust/liblektor-rs/Cargo.toml @@ -17,6 +17,7 @@ license = "MIT" [workspace.dependencies] log = "0.4" libc = "0.2.0" +lazy_static = "1" diesel_migrations = "2" diesel = { version = "2", default-features = false, features = ["sqlite"] } serde = { version = "^1", default-features = false, features = [ @@ -34,4 +35,3 @@ codegen-units = 1 [profile.dev] debug = true opt-level = "s" - diff --git a/src/rust/liblektor-rs/lektor_c_compat/Cargo.toml b/src/rust/liblektor-rs/lektor_c_compat/Cargo.toml index 75e61449..d39190b9 100644 --- a/src/rust/liblektor-rs/lektor_c_compat/Cargo.toml +++ b/src/rust/liblektor-rs/lektor_c_compat/Cargo.toml @@ -8,3 +8,4 @@ license.workspace = true [dependencies] log.workspace = true libc.workspace = true +lazy_static.workspace = true diff --git a/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs b/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs index f522e478..acc5975d 100644 --- a/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs +++ b/src/rust/liblektor-rs/lektor_c_compat/src/c_types.rs @@ -1,10 +1,124 @@ //! Types defined in the C part of the project. Don't use them from safe C code, //! only use the safe wrappers. -pub struct LktQueue; -pub struct LktDb; -pub struct LktUri; +use crate::*; -pub type LktQueuePtr = *mut LktQueue; -pub type LktDbPtr = *mut LktDb; -pub type LktUriPtr = *mut LktUri; +pub type LktQueuePtr = *mut c_void; +pub type LktDbPtr = *mut c_void; +pub type LktUriPtr = *mut c_void; + +#[repr(C)] +pub struct LktEvent { + ty: c_uint, + attr: *const c_void, +} + +#[repr(C)] +pub enum LktUriType { + Null = 0, + Id = 1, + Playlist = 2, + Type = 3, + Author = 4, + Category = 5, + Lanquage = 6, + Query = 7, +} + +#[repr(C)] +pub enum LktUriValueType { + Null = 0, + String = 1, + Integer = 2, +} + +#[repr(C)] +pub enum LktPlaybackEvent { + Stop = 0, + Play = 1, + Pause = 2, + Toggle = 3, +} + +#[repr(C)] +pub enum LktDbUpdateEvent { + Finished = 0, + Progress = 1, +} + +#[repr(C)] +pub enum LktEventType { + Null = 0, + PlayPos = (1 << 1), + PlayFile = (1 << 2), + PlayNext = (1 << 3), + PlayPrev = (1 << 4), + PlayToggle = (1 << 5), + PropVol = (1 << 6), + PropDur = (1 << 7), + PropTime = (1 << 8), + SkipCurrent = (1 << 9), + DbUpdating = (1 << 10), + DbUpdateTotal = (1 << 11), + DbUpdateTick = (1 << 12), + TouchKara = (1 << 13), +} + +impl std::ops::BitOr<u32> for LktEventType { + type Output = u32; + fn bitor(self, rhs: u32) -> Self::Output { + (self as u32) | rhs + } +} + +impl std::ops::BitOr<LktEventType> for u32 { + type Output = u32; + fn bitor(self, rhs: LktEventType) -> Self::Output { + self | (rhs as u32) + } +} + +impl std::ops::BitOr<LktEventType> for LktEventType { + type Output = u32; + fn bitor(self, rhs: LktEventType) -> Self::Output { + (self as u32) | (rhs as u32) + } +} + +#[allow(non_snake_case)] +pub mod LktMacroEvent { + use super::LktEventType::*; + lazy_static::lazy_static! { + pub static ref EVENT_PLAY: u32 = PlayPos | PlayFile | PlayNext | PlayPrev | PlayToggle | SkipCurrent; + pub static ref EVENT_PROP: u32 = PropVol | PropDur | PropTime; + pub static ref LKT_MACRO_EVENT_UPDATE: u32 = DbUpdating | DbUpdateTick | DbUpdateTotal | TouchKara; + } +} + +extern "C" { + pub(crate) fn lkt_uri_get_type(_: LktUriPtr) -> LktUriType; + pub(crate) fn lkt_uri_get_value_as_str(_: LktUriPtr) -> *const c_char; + pub(crate) fn lkt_uri_get_value_as_int(_: LktUriPtr) -> c_int; + pub(crate) fn lkt_uri_get_value_type(_: LktUriPtr) -> LktUriValueType; + pub(crate) fn lkt_uri_get_column_name(_: LktUriPtr) -> *const c_char; +} + +extern "C" { + pub(crate) fn lkt_queue_has_event(_: LktQueuePtr, _: LktEventType) -> bool; + pub(crate) fn lkt_queue_send(_: LktQueuePtr, _: LktEventType, _: *const c_void); + pub(crate) fn lkt_queue_handle(_: LktQueuePtr) -> LktEvent; + pub(crate) fn lkt_queue_make_available(_: LktQueuePtr, _: LktEventType); +} + +unsafe fn str_len(str: *const c_char) -> usize { + let mut ret: isize = 0; + while (*str.offset(ret as _)) != 0 { + ret += 1; + } + ret as usize +} + +pub(crate) unsafe fn ptr_to_str<'a>(str: *const c_char) -> &'a str { + let len = str_len(str); + std::str::from_utf8_unchecked(std::slice::from_raw_parts(str as *const u8, len)) +} diff --git a/src/rust/liblektor-rs/lektor_c_compat/src/lib.rs b/src/rust/liblektor-rs/lektor_c_compat/src/lib.rs index a946a73e..241109ad 100644 --- a/src/rust/liblektor-rs/lektor_c_compat/src/lib.rs +++ b/src/rust/liblektor-rs/lektor_c_compat/src/lib.rs @@ -9,7 +9,7 @@ pub mod c_types; mod rs_types; pub use rs_types::*; -pub use libc::{c_char, c_int, c_long, c_void, size_t}; +pub use libc::{c_char, c_int, c_long, c_uint, c_void, size_t}; /// The maximal length of a tag in lektor. pub const LEKTOR_TAG_MAX: usize = 256; diff --git a/src/rust/liblektor-rs/lektor_c_compat/src/rs_types.rs b/src/rust/liblektor-rs/lektor_c_compat/src/rs_types.rs index 5f914a64..7361a859 100644 --- a/src/rust/liblektor-rs/lektor_c_compat/src/rs_types.rs +++ b/src/rust/liblektor-rs/lektor_c_compat/src/rs_types.rs @@ -1,21 +1,92 @@ use crate::c_types::*; pub struct LktCQueue { - c_ptr: LktQueuePtr, + ptr: LktQueuePtr, +} + +pub enum LktEventValue<'a> { + Null, + Integer(usize), + String(&'a str), } pub struct LktCUri { - c_ptr: LktUriPtr, + ptr: LktUriPtr, } impl From<LktQueuePtr> for LktCQueue { - fn from(c_ptr: LktQueuePtr) -> Self { - Self { c_ptr } + fn from(ptr: LktQueuePtr) -> Self { + Self { ptr } } } impl From<LktUriPtr> for LktCUri { - fn from(c_ptr: LktUriPtr) -> Self { - Self { c_ptr } + fn from(ptr: LktUriPtr) -> Self { + Self { ptr } + } +} + +impl LktCUri { + pub fn get_type(&self) -> LktUriType { + unsafe { lkt_uri_get_type(self.ptr) } + } + + pub fn get_value_type(&self) -> LktUriValueType { + unsafe { lkt_uri_get_value_type(self.ptr) } + } + + pub fn get_value_as_str(&self) -> Option<&str> { + use LktUriValueType::*; + match self.get_value_type() { + Null | Integer => None, + String => Some(unsafe { ptr_to_str(lkt_uri_get_value_as_str(self.ptr)) }), + } + } + + pub fn get_value_as_int(&self) -> Option<i32> { + use LktUriValueType::*; + match self.get_value_type() { + Null | String => None, + Integer => Some(unsafe { lkt_uri_get_value_as_int(self.ptr) }), + } + } + + fn get_column_name(&self) -> &str { + unsafe { ptr_to_str(lkt_uri_get_column_name(self.ptr)) } + } +} + +impl From<LktCUri> for String { + fn from(uri: LktCUri) -> Self { + match uri.get_value_type() { + LktUriValueType::Null => "".to_string(), + LktUriValueType::String => uri.get_value_as_str().unwrap_or_default().to_string(), + LktUriValueType::Integer => uri.get_value_as_int().unwrap_or_default().to_string(), + } + } +} + +impl LktCQueue { + pub fn has_event(&self, ty: LktEventType) -> bool { + unsafe { lkt_queue_has_event(self.ptr, ty) } + } + + pub fn send(&self, ty: LktEventType, val: LktEventValue) { + use LktEventValue::*; + let val = match val { + Null => std::ptr::null(), + Integer(x) => x as *const _, + String(str) => str.as_ptr() as *const _, + }; + unsafe { lkt_queue_send(self.ptr, ty, val) } + todo!("verify validity of (ty, val)") + } + + pub fn handle(&mut self) -> Option<(LktEventType, LktEventValue)> { + todo!("verify validity of (ty, val)") + } + + pub fn make_available(&mut self, ty: LktEventType) { + unsafe { lkt_queue_make_available(self.ptr, ty) } } } diff --git a/src/rust/liblektor-rs/lektor_db/diesel.toml b/src/rust/liblektor-rs/lektor_db/diesel.toml index 8de80930..35a12ff0 100644 --- a/src/rust/liblektor-rs/lektor_db/diesel.toml +++ b/src/rust/liblektor-rs/lektor_db/diesel.toml @@ -2,7 +2,7 @@ # see https://diesel.rs/guides/configuring-diesel-cli [print_schema] -file = "src/database/schema.rs" +file = "src/schema.rs" [migrations_directory] dir = "migrations" diff --git a/src/rust/liblektor-rs/lektor_db/migrations/2022-09-30-204512_initial/up.sql b/src/rust/liblektor-rs/lektor_db/migrations/2022-09-30-204512_initial/up.sql index 7271ce36..dd9b2691 100644 --- a/src/rust/liblektor-rs/lektor_db/migrations/2022-09-30-204512_initial/up.sql +++ b/src/rust/liblektor-rs/lektor_db/migrations/2022-09-30-204512_initial/up.sql @@ -24,7 +24,7 @@ CREATE TABLE kara , song_origin TEXT NOT NULL , source_name TEXT NOT NULL , language TEXT NOT NULL REFERENCES iso_639_1(code) - , file_hash TEXT NOT NULL + , file_hash TEXT NOT NULL UNIQUE ); -- We can have multiple kara makers for one kara. diff --git a/src/rust/liblektor-rs/lektor_db/src/database/schema.rs b/src/rust/liblektor-rs/lektor_db/src/database/schema.rs deleted file mode 100644 index d45ece40..00000000 --- a/src/rust/liblektor-rs/lektor_db/src/database/schema.rs +++ /dev/null @@ -1,86 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - history (epoch) { - id -> Integer, - epoch -> Integer, - } -} - -diesel::table! { - iso_639_1 (code) { - code -> Text, - name_en -> Text, - is_iso -> Bool, - is_macro -> Bool, - } -} - -diesel::table! { - kara (id) { - id -> Integer, - is_dl -> Bool, - song_title -> Text, - song_type -> Text, - song_origin -> Text, - source_name -> Text, - language -> Text, - file_hash -> Text, - } -} - -diesel::table! { - kara_makers (id, name) { - id -> Integer, - name -> Text, - } -} - -diesel::table! { - kara_tags (kara_id, tag_id, value) { - kara_id -> Integer, - tag_id -> Integer, - value -> Nullable<Text>, - } -} - -diesel::table! { - repo (id) { - id -> Integer, - name -> Text, - } -} - -diesel::table! { - repo_kara (repo_id, repo_kara_id, local_kara_id) { - repo_id -> Integer, - repo_kara_id -> Integer, - local_kara_id -> Integer, - } -} - -diesel::table! { - tag (id) { - id -> Integer, - name -> Text, - } -} - -diesel::joinable!(history -> kara (id)); -diesel::joinable!(kara -> iso_639_1 (language)); -diesel::joinable!(kara_makers -> kara (id)); -diesel::joinable!(kara_tags -> kara (kara_id)); -diesel::joinable!(kara_tags -> tag (tag_id)); -diesel::joinable!(repo_kara -> kara (local_kara_id)); -diesel::joinable!(repo_kara -> repo (repo_id)); - -diesel::allow_tables_to_appear_in_same_query!( - history, - iso_639_1, - kara, - kara_makers, - kara_tags, - repo, - repo_kara, - tag, -); -- GitLab