libmandoc-rs 0.10.0

Safe Rust interface to the vendored libmandoc parser and reference renderers
Documentation
//! Bounded native renderer output copied before session release.
#[cfg(windows)]
use super::windows_root;
use super::{
    owned::optional_string,
    raw::{self, CDocument},
    session::{BundleSources, DocumentHandle, input_format_code},
};
use crate::{InputFormat, RawRender, SourceBundle};
#[cfg(windows)]
use std::path::Path;
use std::{ffi::CStr, ptr::NonNull};
#[cfg(all(feature = "render", test))]
pub(crate) fn ctype_locale() -> Option<String> {
    unsafe { optional_string(raw::mant_mandoc_ctype_locale()) }
}

#[cfg(feature = "render")]
pub(crate) struct NativeRenderError {
    pub(crate) status: i32,
    pub(crate) message: String,
}

#[cfg(all(feature = "render", unix))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn render_file(
    path: &CStr,
    include_root: Option<&CStr>,
    allow_includes: bool,
    input_format: InputFormat,
    operating_system: Option<&CStr>,
    render_format: i32,
    width: usize,
    html_fragment: bool,
    output_limit: usize,
) -> Result<RawRender, NativeRenderError> {
    let pointer = unsafe {
        raw::mant_mandoc_render_file(
            path.as_ptr(),
            include_root.map_or(std::ptr::null(), CStr::as_ptr),
            i32::from(allow_includes),
            input_format_code(input_format),
            operating_system.map_or(std::ptr::null(), CStr::as_ptr),
            render_format,
            width,
            i32::from(html_fragment),
            output_limit,
        )
    };
    copy_render(pointer)
}

#[cfg(all(feature = "render", unix))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn render_buffer(
    path: &CStr,
    buffer: &[u8],
    include_root: Option<&CStr>,
    allow_includes: bool,
    input_format: InputFormat,
    operating_system: Option<&CStr>,
    render_format: i32,
    width: usize,
    html_fragment: bool,
    output_limit: usize,
) -> Result<RawRender, NativeRenderError> {
    let pointer = unsafe {
        raw::mant_mandoc_render_buffer(
            path.as_ptr(),
            buffer.as_ptr(),
            buffer.len(),
            include_root.map_or(std::ptr::null(), CStr::as_ptr),
            i32::from(allow_includes),
            input_format_code(input_format),
            operating_system.map_or(std::ptr::null(), CStr::as_ptr),
            render_format,
            width,
            i32::from(html_fragment),
            output_limit,
            None,
            std::ptr::null_mut(),
        )
    };
    copy_render(pointer)
}

#[cfg(all(feature = "render", windows))]
#[allow(clippy::too_many_arguments)]
pub(crate) fn render_buffer(
    path: &CStr,
    buffer: &[u8],
    include_root: Option<&Path>,
    allow_includes: bool,
    input_format: InputFormat,
    operating_system: Option<&CStr>,
    render_format: i32,
    width: usize,
    html_fragment: bool,
    output_limit: usize,
) -> Result<RawRender, NativeRenderError> {
    let mut resolver = include_root.map(|root| windows_root::RootResolver::new(root, path));
    let (callback, context) = windows_root::callback_parts(resolver.as_mut());
    let pointer = unsafe {
        raw::mant_mandoc_render_buffer(
            path.as_ptr(),
            buffer.as_ptr(),
            buffer.len(),
            std::ptr::null(),
            i32::from(allow_includes),
            input_format_code(input_format),
            operating_system.map_or(std::ptr::null(), CStr::as_ptr),
            render_format,
            width,
            i32::from(html_fragment),
            output_limit,
            callback,
            context,
        )
    };
    copy_render(pointer)
}

#[cfg(feature = "render")]
#[allow(clippy::too_many_arguments)]
pub(crate) fn render_bundle(
    root: &CStr,
    bundle: &SourceBundle,
    input_format: InputFormat,
    operating_system: Option<&CStr>,
    render_format: i32,
    width: usize,
    html_fragment: bool,
    output_limit: usize,
) -> Result<RawRender, NativeRenderError> {
    let storage = BundleSources::new(bundle);
    let sources = storage.as_slice();
    let pointer = unsafe {
        raw::mant_mandoc_render_bundle(
            root.as_ptr(),
            sources.as_ptr(),
            sources.len(),
            input_format_code(input_format),
            operating_system.map_or(std::ptr::null(), CStr::as_ptr),
            render_format,
            width,
            i32::from(html_fragment),
            output_limit,
        )
    };
    copy_render(pointer)
}

#[cfg(feature = "render")]
fn copy_render(pointer: *mut CDocument) -> Result<RawRender, NativeRenderError> {
    let handle = DocumentHandle(NonNull::new(pointer).ok_or_else(|| NativeRenderError {
        status: 2,
        message: "libmandoc could not allocate a render result".to_owned(),
    })?);
    let document = handle.0.as_ptr();
    if unsafe { raw::mant_mandoc_document_ok(document) } == 0 {
        return Err(NativeRenderError {
            status: unsafe { raw::mant_mandoc_document_render_status(document) },
            message: unsafe { optional_string(raw::mant_mandoc_document_error(document)) }
                .unwrap_or_else(|| "libmandoc could not render the source".to_owned()),
        });
    }
    let length = unsafe { raw::mant_mandoc_document_output_length(document) };
    let output = unsafe { raw::mant_mandoc_document_output(document) };
    if output.is_null() && length != 0 {
        return Err(NativeRenderError {
            status: 2,
            message: "libmandoc returned an invalid render buffer".to_owned(),
        });
    }
    Ok(RawRender {
        output: if length == 0 {
            Vec::new()
        } else {
            unsafe { std::slice::from_raw_parts(output, length) }.to_vec()
        },
        diagnostics: unsafe {
            optional_string(raw::mant_mandoc_document_diagnostics(document)).unwrap_or_default()
        },
    })
}