Skip to content
Extraits de code Groupes Projets
Vérifiée Valider dc8fa1aa rédigé par Kubat's avatar Kubat
Parcourir les fichiers

[WIP] RUST: Implementing the safe interface over the unsafe C types and functions

parent 36d0a40a
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -17,6 +17,7 @@ license = "MIT" ...@@ -17,6 +17,7 @@ license = "MIT"
[workspace.dependencies] [workspace.dependencies]
log = "0.4" log = "0.4"
libc = "0.2.0" libc = "0.2.0"
lazy_static = "1"
diesel_migrations = "2" diesel_migrations = "2"
diesel = { version = "2", default-features = false, features = ["sqlite"] } diesel = { version = "2", default-features = false, features = ["sqlite"] }
serde = { version = "^1", default-features = false, features = [ serde = { version = "^1", default-features = false, features = [
...@@ -34,4 +35,3 @@ codegen-units = 1 ...@@ -34,4 +35,3 @@ codegen-units = 1
[profile.dev] [profile.dev]
debug = true debug = true
opt-level = "s" opt-level = "s"
...@@ -8,3 +8,4 @@ license.workspace = true ...@@ -8,3 +8,4 @@ license.workspace = true
[dependencies] [dependencies]
log.workspace = true log.workspace = true
libc.workspace = true libc.workspace = true
lazy_static.workspace = true
//! Types defined in the C part of the project. Don't use them from safe C code, //! Types defined in the C part of the project. Don't use them from safe C code,
//! only use the safe wrappers. //! only use the safe wrappers.
pub struct LktQueue; use crate::*;
pub struct LktDb;
pub struct LktUri;
pub type LktQueuePtr = *mut LktQueue; pub type LktQueuePtr = *mut c_void;
pub type LktDbPtr = *mut LktDb; pub type LktDbPtr = *mut c_void;
pub type LktUriPtr = *mut LktUri; 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))
}
...@@ -9,7 +9,7 @@ pub mod c_types; ...@@ -9,7 +9,7 @@ pub mod c_types;
mod rs_types; mod rs_types;
pub use 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. /// The maximal length of a tag in lektor.
pub const LEKTOR_TAG_MAX: usize = 256; pub const LEKTOR_TAG_MAX: usize = 256;
use crate::c_types::*; use crate::c_types::*;
pub struct LktCQueue { pub struct LktCQueue {
c_ptr: LktQueuePtr, ptr: LktQueuePtr,
}
pub enum LktEventValue<'a> {
Null,
Integer(usize),
String(&'a str),
} }
pub struct LktCUri { pub struct LktCUri {
c_ptr: LktUriPtr, ptr: LktUriPtr,
} }
impl From<LktQueuePtr> for LktCQueue { impl From<LktQueuePtr> for LktCQueue {
fn from(c_ptr: LktQueuePtr) -> Self { fn from(ptr: LktQueuePtr) -> Self {
Self { c_ptr } Self { ptr }
} }
} }
impl From<LktUriPtr> for LktCUri { impl From<LktUriPtr> for LktCUri {
fn from(c_ptr: LktUriPtr) -> Self { fn from(ptr: LktUriPtr) -> Self {
Self { c_ptr } 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) }
} }
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# see https://diesel.rs/guides/configuring-diesel-cli # see https://diesel.rs/guides/configuring-diesel-cli
[print_schema] [print_schema]
file = "src/database/schema.rs" file = "src/schema.rs"
[migrations_directory] [migrations_directory]
dir = "migrations" dir = "migrations"
...@@ -24,7 +24,7 @@ CREATE TABLE kara ...@@ -24,7 +24,7 @@ CREATE TABLE kara
, song_origin TEXT NOT NULL , song_origin TEXT NOT NULL
, source_name TEXT NOT NULL , source_name TEXT NOT NULL
, language TEXT NOT NULL REFERENCES iso_639_1(code) , 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. -- We can have multiple kara makers for one kara.
......
// @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,
);
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter