Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log #61

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open

Log #61

Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b0fce0c
init lv2-log crate
YruamaLairba Mar 25, 2020
79e0864
implement feature part of log
YruamaLairba Mar 26, 2020
101d936
impl Uribound and LogURIDcollection for type of log
YruamaLairba Mar 26, 2020
875153c
usable but unsafe draft
YruamaLairba Mar 26, 2020
3d3a31e
avoid '%' be interpreted, Format code
YruamaLairba Mar 29, 2020
862fa63
check for null string terminator for safety
YruamaLairba Mar 29, 2020
92691a4
create and use LogError enum
YruamaLairba Mar 29, 2020
eca5acd
Copy as supertrait for entry urid
YruamaLairba Apr 1, 2020
40ea7b7
add some doc
YruamaLairba Apr 1, 2020
36bf4fe
restrict log feature to the instantiation threading class
YruamaLairba Apr 2, 2020
fe6d8d7
WIP
YruamaLairba Apr 6, 2020
575a626
Merge branch 'develop' into log
YruamaLairba Aug 10, 2021
0eff4b0
fix the code after merge
YruamaLairba Aug 10, 2021
5eb55ab
apply prokopyl suggestion to refactor code
YruamaLairba Aug 10, 2021
d278053
forbid log feature only in the audio threading class
YruamaLairba Aug 10, 2021
a5c2d6f
change print to print_cstr
YruamaLairba Aug 17, 2021
5226867
remove println, it's not needed and almost useless
YruamaLairba Aug 17, 2021
97c4175
fix EntryType marker trait
YruamaLairba Aug 17, 2021
f6fd9ee
use a custom type to not have function pointer inside Option
YruamaLairba Aug 19, 2021
30656af
replace LogError by PrintError
YruamaLairba Aug 19, 2021
6e0ee4a
shorten the name and redocument URID marker
YruamaLairba Aug 19, 2021
826aeb0
ooops, log is not rt-safe but is valid in any threading class
YruamaLairba Aug 19, 2021
f0a47aa
oops, forgot to remove some _class suffix
YruamaLairba Aug 19, 2021
99e12cc
use a pointer replacement.
YruamaLairba Aug 20, 2021
ed9613b
complete and rework the log crate doc
YruamaLairba Aug 21, 2021
5134b89
fix example test (missing dev dependencie)
YruamaLairba Aug 21, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ members = [
"atom",
"core",
"core/derive",
"log",
"midi",
"state",
"sys",
Expand Down
12 changes: 12 additions & 0 deletions log/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "lv2-log"
version = "0.1.0"
authors = ["Yruama_Lairba <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lv2-sys = "2.0.0"
lv2-core = "3.0.0"
urid = "0.1.0"
167 changes: 167 additions & 0 deletions log/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use lv2_core::feature::{Feature, ThreadingClass};
//use std::ffi::CString;
use std::os::raw::*; //get all common c_type
use urid::*;

pub struct EntryClass;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having the entry types in a submodule (entries for instance) would be a cleaner, although it's not a lot of code, it'll show up as quite a few types in the rustdoc and might be a bit overwhelming for new users that might want to focus elsewhere (mainly the Log feature, or the entry type trait).

unsafe impl UriBound for EntryClass {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
const URI: &'static [u8] = lv2_sys::LV2_LOG__Entry;
}

/// UriBound for an error message.
pub struct ErrorClass;
unsafe impl UriBound for ErrorClass {
const URI: &'static [u8] = lv2_sys::LV2_LOG__Error;
}

/// UriBound for an informative message.
pub struct NoteClass;
unsafe impl UriBound for NoteClass {
const URI: &'static [u8] = lv2_sys::LV2_LOG__Note;
}

/// UriBound for a debuging message.
pub struct TraceClass;
unsafe impl UriBound for TraceClass {
const URI: &'static [u8] = lv2_sys::LV2_LOG__Trace;
}

/// Uribound for an error message.
pub struct WarningClass;
unsafe impl UriBound for WarningClass {
const URI: &'static [u8] = lv2_sys::LV2_LOG__Warning;
}

/// Marker for URID representing the nature of a log message.
// Note : it's may be better to have a URID trait to define a common interface
pub unsafe trait EntryType
where
Self: Copy,
{
}

unsafe impl EntryType for URID<ErrorClass> {}
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
unsafe impl EntryType for URID<NoteClass> {}
unsafe impl EntryType for URID<TraceClass> {}
unsafe impl EntryType for URID<WarningClass> {}

/// Errors potentially generated by [`Log`](struct.Log.html) methods.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum LogError {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
/// An error occured when sending message to the host
PrintError,
/// The provided string don't have a `'\0'` to indicate it's end
NoNullTerminator,
/// No callback was provided by the host
///
/// This can only happen with a faulty host
NoCallback,
}

/// The Log feature.
#[repr(transparent)]
pub struct Log<'a> {
internal: &'a lv2_sys::LV2_Log_Log,
}

unsafe impl<'a> UriBound for Log<'a> {
const URI: &'static [u8] = lv2_sys::LV2_LOG__log;
}

unsafe impl<'a> Feature for Log<'a> {
// Note: this feature can be used in any threading class but:
// * i have a doubt about it's thread safety, can we assume the host provide this thread safety
// since this feature can be used anywhere ?.
// * i shouldn't be used in context where rt is a concern, that mean is audiothreadclass in
// practice, but it's acceptable to use it for debugging purpose
// So, at this time, i just giving access to it instanciation class
unsafe fn from_feature_ptr(feature: *const c_void, class: ThreadingClass) -> Option<Self> {
match class {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
ThreadingClass::Audio => {
panic!("The log feature is not allowed in the audio threading class")
}
_ => (feature as *const lv2_sys::LV2_Log_Log)
.as_ref()
.map(|internal| Self { internal }),
}
}
}

impl<'a> Log<'a> {
/// Send a log message to the host.
///
/// The `entry_type` parameter is an URID representing the kind of log message. There are four
/// kind of message:
/// * **note:** an informative message.
/// * **warning:** a warning message.
/// * **error:** an error message.
/// * **trace:** a debugging trace. These entries should not be displayed during normal
/// operation, but the host may implement an option to display them for debugging purposes.
/// This entry type is special in that it may be written to in a real-time thread. It is
/// assumed that if debug tracing is enabled, real-time considerations are not a concern.
pub fn print(&self, entry_type: URID<impl EntryType>, message: &str) -> Result<(), LogError> {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
let printf = if let Some(printf) = self.internal.printf {
printf
} else {
return Err(LogError::NoCallback);
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
};
let message = String::from(message) + "\0";

let res = unsafe {
(printf)(
self.internal.handle,
entry_type.get(),
"%s\0" as *const _ as *const c_char,
message.as_str() as *const _ as *const c_char,
)
};
if res > 0 {
Ok(())
} else {
Err(LogError::PrintError)
}
}
/// Send a message to the host with a new line at the end.
///
/// It same as [print](struct.Log.html#method.print) but add a newline a the end of message.
/// See [print](struct.Log.html#method.print) documentation for details.
pub fn println(&self, entry_type: URID<impl EntryType>, message: &str) -> Result<(), LogError> {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
let printf = if let Some(printf) = self.internal.printf {
printf
} else {
return Err(LogError::NoCallback);
};
let message = String::from(message) + "\n\0";

let res = unsafe {
(printf)(
self.internal.handle,
entry_type.get(),
"%s\0" as *const _ as *const c_char,
message.as_str() as *const _ as *const c_char,
)
};
if res > 0 {
Ok(())
} else {
Err(LogError::PrintError)
}
}
}

/// A URID cache containing all log properties.
#[derive(URIDCollection, Debug)]
pub struct LogURIDCollection {
pub entry_class: URID<EntryClass>,
pub error_class: URID<ErrorClass>,
pub note_class: URID<NoteClass>,
pub trace_class: URID<TraceClass>,
pub warning_class: URID<WarningClass>,
//pub log: URID<Log<'a>>,
}

#[cfg(test)]
mod tests {
YruamaLairba marked this conversation as resolved.
Show resolved Hide resolved
#[test]
fn it_works() {}
}