use importer::classic_song::slides_from_classic_song;
use importer::errors::*;
use slides::{ShowMetaInformation, Slide, SlideSettings};
use std::error::Error;
use std::ffi::{c_char, c_int, CStr, CString};
use std::path::PathBuf;
pub mod song;
pub mod importer;
pub mod filetypes;
pub mod slides;
pub mod templating;
#[no_mangle]
pub extern "C" fn create_presentation_from_file_c(
c_file_path: *const c_char,
c_title_slide: c_int,
c_show_spoiler: c_int,
c_show_meta_information: c_int,
c_meta_syntax: *const c_char,
c_empty_last_side: c_int,
c_max_lines: c_int
) -> *const c_char {
let file_path: PathBuf = PathBuf::from(c_string_to_rust(c_file_path).unwrap());
let title_slide: bool = match c_title_slide as i32 {
1 => true,
_ => false
};
let show_spoiler: bool = match c_show_spoiler as i32 {
1 => true,
_ => false
};
let show_meta_information: ShowMetaInformation = match c_show_meta_information {
1 => ShowMetaInformation::FirstSlide,
2 => ShowMetaInformation::LastSlide,
3 => ShowMetaInformation::FirstSlideAndLastSlide,
_ => ShowMetaInformation::None,
};
let meta_syntax = c_string_to_rust(c_meta_syntax).unwrap();
let empty_last_slide: bool = match c_empty_last_side {
1 => true,
_ => false
};
let max_lines: Option<usize> = match c_max_lines as usize {
0 => None,
_ => Some(c_max_lines as usize)
};
let slide_settings: SlideSettings = SlideSettings {
title_slide,
show_spoiler,
show_meta_information,
meta_syntax,
empty_last_slide,
max_lines
};
match create_presentation_from_file(file_path, slide_settings) {
Ok(v) => rust_string_to_c_char(serde_json::to_string(&v).unwrap()).unwrap(),
Err(err) => rust_string_to_c_char(err.to_string()).unwrap(),
}
}
pub fn create_presentation_from_file(file_path: PathBuf, slide_settings: SlideSettings) -> Result<Vec<Slide>, Box<dyn Error>> {
if !file_path.exists() {
return Err(
Box::new(CantaraFileDoesNotExistError)
)
}
if file_path.extension() == Some(std::ffi::OsStr::new("song")) {
let file_content = std::fs::read_to_string(&file_path).unwrap();
let slides = slides_from_classic_song(
&file_content,
&slide_settings,
file_path.file_stem().unwrap().to_str().unwrap().to_string()
);
return Ok(slides);
}
Err(
Box::new(
CantaraImportUnknownFileExtensionError {
file_extension: "unknown".to_string()
}
)
)
}
fn c_string_to_rust(c_str: *const c_char) -> Option<String> {
if c_str.is_null() {
return None; }
unsafe {
let cstr = CStr::from_ptr(c_str);
cstr.to_str()
.map(|s| s.to_string()) .ok() }
}
fn rust_string_to_c_char(rust_str: String) -> Option<*const c_char> {
match CString::new(rust_str) {
Ok(c_string) => {
let c_ptr = c_string.as_ptr();
std::mem::forget(c_string); Some(c_ptr)
}
Err(_) => {
None
}
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::{create_presentation_from_file, slides::SlideSettings};
use super::song::Song;
#[test]
fn create_example_song() {
let song: Song = Song::new("Test Song");
assert_eq!(song.title, "Test Song");
assert_eq!(song.get_total_part_count(), 0);
assert_eq!(song.get_unpacked_parts().len(), 0)
}
#[test]
fn test_file_does_not_exist_error() {
let file_path: PathBuf = "Ich existiere nicht.song".into();
let slide_settings: SlideSettings = SlideSettings::default();
assert!(
create_presentation_from_file(file_path, slide_settings)
.is_err()
)
}
}