use std::ptr::NonNull;
use crate::editor::{Segment, borrow_str, to_ffi_keys, to_ffi_path};
use crate::error::Error;
use crate::value::{Value, value_text};
use crate::{Format, ffi};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EmbedType {
FrontmatterYaml,
FrontmatterJson,
EndmatterYaml,
}
impl EmbedType {
fn ffi(self) -> ffi::FigEmbedType {
match self {
EmbedType::FrontmatterYaml => ffi::FigEmbedType::FrontmatterYaml,
EmbedType::FrontmatterJson => ffi::FigEmbedType::FrontmatterJson,
EmbedType::EndmatterYaml => ffi::FigEmbedType::EndmatterYaml,
}
}
fn inner_format(self) -> Format {
match self {
EmbedType::FrontmatterYaml | EmbedType::EndmatterYaml => Format::Yaml,
EmbedType::FrontmatterJson => Format::Json,
}
}
}
#[derive(Debug)]
pub struct Embed {
raw: NonNull<ffi::FigEmbed>,
inner: Format,
}
impl Embed {
pub fn open(host: &[u8], kind: EmbedType) -> Result<Self, Error> {
let mut raw = std::ptr::null_mut();
let status =
unsafe { ffi::fig_embed_open(host.as_ptr(), host.len(), kind.ffi() as i32, &mut raw) };
Error::from_status(status)?;
let raw = NonNull::new(raw).ok_or(Error::Internal)?;
Ok(Self {
raw,
inner: kind.inner_format(),
})
}
pub fn frontmatter(markdown: &[u8]) -> Result<Self, Error> {
Self::open(markdown, EmbedType::FrontmatterYaml)
}
fn ptr(&self) -> *mut ffi::FigEmbed {
self.raw.as_ptr()
}
pub fn replace_value(&mut self, path: &[Segment], value: &Value) -> Result<(), Error> {
let repl = value_text(value, self.inner)?;
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_replace_val(self.ptr(), p.as_ptr(), p.len(), repl.as_ptr(), repl.len())
};
Error::from_status(status)
}
pub fn replace_key(&mut self, path: &[Segment], key: &str) -> Result<(), Error> {
let repl = value_text(&Value::Str(key.to_string()), self.inner)?;
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_replace_key(self.ptr(), p.as_ptr(), p.len(), repl.as_ptr(), repl.len())
};
Error::from_status(status)
}
pub fn insert_value(
&mut self,
path: &[Segment],
key: &str,
value: &Value,
) -> Result<(), Error> {
let key_text = value_text(&Value::Str(key.to_string()), self.inner)?;
let val = value_text(value, self.inner)?;
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_insert_key(
self.ptr(),
p.as_ptr(),
p.len(),
key_text.as_ptr(),
key_text.len(),
val.as_ptr(),
val.len(),
)
};
Error::from_status(status)
}
pub fn append_value(&mut self, path: &[Segment], value: &Value) -> Result<(), Error> {
let val = value_text(value, self.inner)?;
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_append_seq(self.ptr(), p.as_ptr(), p.len(), val.as_ptr(), val.len())
};
Error::from_status(status)
}
pub fn prepend_value(&mut self, path: &[Segment], value: &Value) -> Result<(), Error> {
let val = value_text(value, self.inner)?;
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_prepend_seq(self.ptr(), p.as_ptr(), p.len(), val.as_ptr(), val.len())
};
Error::from_status(status)
}
#[cfg(feature = "serde")]
pub fn replace<T: serde::Serialize + ?Sized>(
&mut self,
path: &[Segment],
value: &T,
) -> Result<(), Error> {
self.replace_value(path, &crate::ser::to_value(value)?)
}
#[cfg(feature = "serde")]
pub fn insert<T: serde::Serialize + ?Sized>(
&mut self,
path: &[Segment],
key: &str,
value: &T,
) -> Result<(), Error> {
self.insert_value(path, key, &crate::ser::to_value(value)?)
}
#[cfg(feature = "serde")]
pub fn append<T: serde::Serialize + ?Sized>(
&mut self,
path: &[Segment],
value: &T,
) -> Result<(), Error> {
self.append_value(path, &crate::ser::to_value(value)?)
}
#[cfg(feature = "serde")]
pub fn prepend<T: serde::Serialize + ?Sized>(
&mut self,
path: &[Segment],
value: &T,
) -> Result<(), Error> {
self.prepend_value(path, &crate::ser::to_value(value)?)
}
pub fn add_leading_comment(&mut self, path: &[Segment], text: &str) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_add_leading_comment(self.ptr(), p.as_ptr(), p.len(), text.as_ptr(), text.len())
};
Error::from_status(status)
}
pub fn set_trailing_comment(&mut self, path: &[Segment], text: &str) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_set_trailing_comment(self.ptr(), p.as_ptr(), p.len(), text.as_ptr(), text.len())
};
Error::from_status(status)
}
pub fn delete_leading_comments(&mut self, path: &[Segment]) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe { ffi::fig_embed_delete_leading_comments(self.ptr(), p.as_ptr(), p.len()) };
Error::from_status(status)
}
pub fn delete_trailing_comment(&mut self, path: &[Segment]) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe { ffi::fig_embed_delete_trailing_comment(self.ptr(), p.as_ptr(), p.len()) };
Error::from_status(status)
}
pub fn delete(&mut self, path: &[Segment]) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe { ffi::fig_embed_delete_key(self.ptr(), p.as_ptr(), p.len()) };
Error::from_status(status)
}
pub fn remove_item(&mut self, path: &[Segment], index: usize) -> Result<(), Error> {
let p = to_ffi_path(path);
let status =
unsafe { ffi::fig_embed_remove_seq_item(self.ptr(), p.as_ptr(), p.len(), index) };
Error::from_status(status)
}
pub fn move_key(&mut self, src_path: &[Segment], dest_path: &[Segment]) -> Result<(), Error> {
let s = to_ffi_path(src_path);
let d = to_ffi_path(dest_path);
let status = unsafe {
ffi::fig_embed_move_key(self.ptr(), s.as_ptr(), s.len(), d.as_ptr(), d.len())
};
Error::from_status(status)
}
pub fn reorder_keys<S: AsRef<str>>(
&mut self,
path: &[Segment],
keys: &[S],
) -> Result<(), Error> {
let p = to_ffi_path(path);
let k = to_ffi_keys(keys);
let status = unsafe {
ffi::fig_embed_reorder_keys(self.ptr(), p.as_ptr(), p.len(), k.as_ptr(), k.len())
};
Error::from_status(status)
}
pub fn move_item(&mut self, path: &[Segment], from: usize, to: usize) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe { ffi::fig_embed_move_item(self.ptr(), p.as_ptr(), p.len(), from, to) };
Error::from_status(status)
}
pub fn reorder_items(&mut self, path: &[Segment], indices: &[usize]) -> Result<(), Error> {
let p = to_ffi_path(path);
let status = unsafe {
ffi::fig_embed_reorder_items(
self.ptr(),
p.as_ptr(),
p.len(),
indices.as_ptr(),
indices.len(),
)
};
Error::from_status(status)
}
pub fn render(&mut self) -> Result<&str, Error> {
let mut ptr: *const u8 = std::ptr::null();
let mut len: usize = 0;
let status = unsafe { ffi::fig_embed_render(self.raw.as_ptr(), &mut ptr, &mut len) };
Error::from_status(status)?;
borrow_str(ptr, len)
}
}
impl Drop for Embed {
fn drop(&mut self) {
unsafe { ffi::fig_embed_destroy(self.raw.as_ptr()) };
}
}