//! FFI interface for `rustc_format_parser` use std::alloc::Layout; // what's the plan? Have a function return something that can be constructed into a vector?// or an iterator? trait IntoFFI<T> { fn into_ffi(self) -> T;} // FIXME: Make an ffi module in a separate file// FIXME: Remember to leak the boxed type somehow// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T> -> *const T could work maybe?pub mod ffi { use super::IntoFFI; use std::marker::PhantomData; use std::mem::MaybeUninit; #[repr(C)] pub struct FFIVec<T> { data: *mut T, len: usize, cap: usize } impl<T> IntoFFI<FFIVec<T>> for Vec<T> { fn into_ffi(mut self) -> FFIVec<T> { let ret = FFIVec { data: self.as_mut_ptr(), len: self.len(), cap: self.capacity() }; self.leak(); ret } } impl<T> Drop for FFIVec<T> { fn drop(&mut self) { unsafe { Vec::from_raw_parts(self.data, self.len, self.cap); } } } impl<T> FFIVec<T> { fn with_vec_ref<R, F: for<'a> FnOnce(&'a Vec<T>) -> R>( &self, f: F ) -> R { let v = unsafe { Vec::from_raw_parts(self.data, self.len, self.cap) }; let ret = f(&v); v.leak(); ret } // currently unused // may be nice to have later, though #[allow(unused)] fn with_vec_mut_ref<R, F: for<'a> FnOnce(&'a mut Vec<T>) -> R>( &mut self, f: F ) -> R { let mut v = unsafe { Vec::from_raw_parts(self.data, self.len, self.cap) }; let ret = f(&mut v); self.data = v.as_mut_ptr(); self.len = v.len(); self.cap = v.capacity(); v.leak(); ret } } impl<T> Clone for FFIVec<T> where T: Clone { fn clone(&self) -> FFIVec<T> { self.with_vec_ref(|v| v.clone().into_ffi()) } } // https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md #[repr(u8)] #[derive(Copy, Clone, PartialEq, Eq)] pub enum FFIOpt<T> { Some(T), None } impl<T> IntoFFI<FFIOpt<T>> for Option<T> { fn into_ffi(self) -> FFIOpt<T> { match self { Some(v) => FFIOpt::Some(v), None => FFIOpt::None } } } // FIXME: We need to ensure we deal with memory properly - whether it's owned by the C++ side or the Rust side #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[repr(C)] pub struct RustHamster<'a> { ptr: *const u8, len: usize, phantom: PhantomData<&'a u8> } impl<'a> IntoFFI<RustHamster<'a>> for &'a str { fn into_ffi(self) -> RustHamster<'a> { RustHamster { ptr: self.as_ptr(), len: self.len(), phantom: PhantomData, } } } impl<'a> RustHamster<'a> { pub fn as_str(&self) -> &'a str { unsafe { let slice: &'a [u8] = std::slice::from_raw_parts(self.ptr, self.len); std::str::from_utf8_unchecked(slice) } } } // Note: copied from rustc_span /// Range inside of a `Span` used for diagnostics when we only have access to relative positions. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[repr(C)] pub struct InnerSpan { pub start: usize, pub end: usize, } /// The location and before/after width of a character whose width has changed from its source code /// representation #[derive(Copy, Clone, PartialEq, Eq)] #[repr(C)] pub struct InnerWidthMapping { /// Index of the character in the source pub position: usize, /// The inner width in characters pub before: usize, /// The transformed width in characters pub after: usize, } // TODO: Not needed for now? // /// Whether the input string is a literal. If yes, it contains the inner width mappings. // #[derive(Clone, PartialEq, Eq)] // #[repr(C)] // enum InputStringKind { // NotALiteral, // Literal { // width_mappings: Vec<InnerWidthMapping>, // }, // } // TODO: Not needed for now? // /// The type of format string that we are parsing. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(C)] pub enum ParseMode { /// A normal format string as per `format_args!`. Format = 0, /// An inline assembly template string for `asm!`. InlineAsm, } /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Clone)] #[repr(C)] pub enum Piece<'a> { /// A literal string which should directly be emitted String(RustHamster<'a>), /// This describes that formatting should process the next argument (as /// specified inside) for emission. // do we need a pointer here? we're doing big cloning anyway NextArgument(Argument<'a>), } /// Representation of an argument specification. #[derive(Clone)] #[repr(C)] pub struct Argument<'a> { /// Where to find this argument pub position: Position<'a>, /// The span of the position indicator. Includes any whitespace in implicit /// positions (`{ }`). pub position_span: InnerSpan, /// How to format the argument pub format: FormatSpec<'a>, } /// Specification for the formatting of an argument in the format string. #[derive(Clone)] #[repr(C)] pub struct FormatSpec<'a> { /// Optionally specified character to fill alignment with. pub fill: FFIOpt<char>, /// Span of the optionally specified fill character. pub fill_span: FFIOpt<InnerSpan>, /// Optionally specified alignment. pub align: Alignment, /// The `+` or `-` flag. pub sign: FFIOpt<Sign>, /// The `#` flag. pub alternate: bool, /// The `0` flag. pub zero_pad: bool, /// The `x` or `X` flag. (Only for `Debug`.) pub debug_hex: FFIOpt<DebugHex>, /// The integer precision to use. pub precision: Count<'a>, /// The span of the precision formatting flag (for diagnostics). pub precision_span: FFIOpt<InnerSpan>, /// The string width requested for the resulting format. pub width: Count<'a>, /// The span of the width formatting flag (for diagnostics). pub width_span: FFIOpt<InnerSpan>, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. pub ty: RustHamster<'a>, /// The span of the descriptor string (for diagnostics). pub ty_span: FFIOpt<InnerSpan>, } /// Enum describing where an argument for a format can be located. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum Position<'a> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format, ArgumentIs(usize), /// The argument has a name. ArgumentNamed(RustHamster<'a>), } /// Enum of alignments which are supported. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum Alignment { /// The value will be aligned to the left. AlignLeft, /// The value will be aligned to the right. AlignRight, /// The value will be aligned in the center. AlignCenter, /// The value will take on a default alignment. AlignUnknown, } /// Enum for the sign flags. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum Sign { /// The `+` flag. Plus, /// The `-` flag. Minus, } /// Enum for the debug hex flags. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum DebugHex { /// The `x` flag in `{:x?}`. Lower, /// The `X` flag in `{:X?}`. Upper, } /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. #[derive(Copy, Clone, Debug, PartialEq)] #[repr(C)] pub enum Count<'a> { /// The count is specified explicitly. CountIs(usize), /// The count is specified by the argument with the given name. CountIsName(RustHamster<'a>, InnerSpan), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. CountIsStar(usize), /// The count is implied and cannot be explicitly specified. CountImplied, } impl<'a> From<generic_format_parser::Piece<'a>> for Piece<'a> { fn from(old: generic_format_parser::Piece<'a>) -> Self { match old { generic_format_parser::Piece::String(x) => Piece::String(x.into_ffi()), generic_format_parser::Piece::NextArgument(x) => { // FIXME: This is problematic - if we do this, then we probably run into the issue that the Box // is freed at the end of the call to collect_pieces. if we just .leak() it, then we have // a memory leak... should we resend the info back to the Rust lib afterwards to free it? // this is definitely the best way - store that pointer in the FFI piece and rebuild the box // in a Rust destructor let ptr = Box::leak(x); let dst = Into::<Argument>::into(*ptr); Piece::NextArgument(dst) } } } } impl<'a> From<generic_format_parser::Argument<'a>> for Argument<'a> { fn from(old: generic_format_parser::Argument<'a>) -> Self { Argument { position: old.position.into(), position_span: old.position_span.into(), format: old.format.into(), } } } impl<'a> From<generic_format_parser::Position<'a>> for Position<'a> { fn from(old: generic_format_parser::Position<'a>) -> Self { match old { generic_format_parser::Position::ArgumentImplicitlyIs(x) => { Position::ArgumentImplicitlyIs(x.into()) } generic_format_parser::Position::ArgumentIs(x) => Position::ArgumentIs(x.into()), generic_format_parser::Position::ArgumentNamed(x) => { Position::ArgumentNamed(x.into_ffi()) } } } } impl From<generic_format_parser::InnerSpan> for InnerSpan { fn from(old: generic_format_parser::InnerSpan) -> Self { InnerSpan { start: old.start, end: old.end, } } } impl<'a> From<generic_format_parser::FormatSpec<'a>> for FormatSpec<'a> { fn from(old: generic_format_parser::FormatSpec<'a>) -> Self { FormatSpec { fill: old.fill.into_ffi(), fill_span: old.fill_span.map(Into::into).into_ffi(), align: old.align.into(), sign: old.sign.map(Into::into).into_ffi(), alternate: old.alternate, zero_pad: old.zero_pad, debug_hex: old.debug_hex.map(Into::into).into_ffi(), precision: old.precision.into(), precision_span: old.precision_span.map(Into::into).into_ffi(), width: old.width.into(), width_span: old.width_span.map(Into::into).into_ffi(), ty: old.ty.into_ffi(), ty_span: old.ty_span.map(Into::into).into_ffi(), } } } impl From<generic_format_parser::DebugHex> for DebugHex { fn from(old: generic_format_parser::DebugHex) -> Self { match old { generic_format_parser::DebugHex::Lower => DebugHex::Lower, generic_format_parser::DebugHex::Upper => DebugHex::Upper, } } } impl<'a> From<generic_format_parser::Count<'a>> for Count<'a> { fn from(old: generic_format_parser::Count<'a>) -> Self { match old { generic_format_parser::Count::CountIs(x) => Count::CountIs(x), generic_format_parser::Count::CountIsName(x, y) => Count::CountIsName(x.into_ffi(), y.into()), generic_format_parser::Count::CountIsParam(x) => Count::CountIsParam(x), generic_format_parser::Count::CountIsStar(x) => Count::CountIsStar(x), generic_format_parser::Count::CountImplied => Count::CountImplied, } } } impl From<generic_format_parser::Sign> for Sign { fn from(old: generic_format_parser::Sign) -> Self { match old { generic_format_parser::Sign::Plus => Sign::Plus, generic_format_parser::Sign::Minus => Sign::Minus, } } } impl From<generic_format_parser::Alignment> for Alignment { fn from(old: generic_format_parser::Alignment) -> Self { match old { generic_format_parser::Alignment::AlignLeft => Alignment::AlignLeft, generic_format_parser::Alignment::AlignRight => Alignment::AlignRight, generic_format_parser::Alignment::AlignCenter => Alignment::AlignCenter, generic_format_parser::Alignment::AlignUnknown => Alignment::AlignUnknown, } } }} // FIXME: Rename?pub mod rust { use crate::ffi::ParseMode; use generic_format_parser::{Parser, Piece}; pub fn collect_pieces( input: &str, style: Option<usize>, snippet: Option<String>, append_newline: bool, parse_mode: ParseMode, ) -> Vec<Piece<'_>> { let converted_parse_mode = match parse_mode { ParseMode::Format => generic_format_parser::ParseMode::Format, ParseMode::InlineAsm => generic_format_parser::ParseMode::InlineAsm, }; let parser = Parser::new(input, style, snippet, append_newline, converted_parse_mode); parser.into_iter().collect() }} // TODO: Should we instead make an FFIVector struct?type PieceVec<'a> = ffi::FFIVec<ffi::Piece<'a>>; #[no_mangle]pub extern "C" fn collect_pieces<'a>( input: ffi::RustHamster<'a>, append_newline: bool, parse_mode: crate::ffi::ParseMode,) -> PieceVec<'a> { // FIXME: No unwrap let pieces: Vec<ffi::Piece<'_>> = rust::collect_pieces(input.as_str(), None, None, append_newline, parse_mode) .into_iter() .map(Into::into) .collect(); pieces.into_ffi()} #[no_mangle]pub extern "C" fn clone_pieces<'a, 'b>( piece_vec: &'a PieceVec<'b>) -> PieceVec<'b> { piece_vec.clone()} // we need Layout::repeat// function signature is a bit different, so call it repeat_xtrait LayoutExt { fn repeat_x(&self, n: usize) -> Layout;} impl LayoutExt for Layout { fn repeat_x(&self, n: usize) -> Layout { let elem = self.pad_to_align(); let total_size = elem.size().checked_mul(n).unwrap(); Layout::from_size_align(total_size, elem.align()).unwrap() }} #[no_mangle]pub unsafe extern "C" fn rust_ffi_alloc( count: usize, elem_size: usize, align: usize) -> *mut u8 { unsafe { std::alloc::alloc( Layout::from_size_align_unchecked(elem_size, align) .repeat_x(count) ) }} #[no_mangle]pub unsafe extern "C" fn rust_ffi_dealloc( data: *mut u8, count: usize, elem_size: usize, align: usize) { unsafe { std::alloc::dealloc( data, Layout::from_size_align_unchecked(elem_size, align) .repeat_x(count) ) }}
//! FFI interface for `rustc_format_parser`
use std::alloc::Layout;
// what's the plan? Have a function return something that can be constructed into a vector?
// or an iterator?
trait IntoFFI<T> {
fn into_ffi(self) -> T;
}
// FIXME: Make an ffi module in a separate file
// FIXME: Remember to leak the boxed type somehow
// FIXME: How to encode the Option type? As a pointer? Option<T> -> Option<&T> -> *const T could work maybe?
pub mod ffi {
use super::IntoFFI;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
#[repr(C)]
pub struct FFIVec<T> {
data: *mut T,
len: usize,
cap: usize
}
impl<T> IntoFFI<FFIVec<T>> for Vec<T> {
fn into_ffi(mut self) -> FFIVec<T> {
let ret = FFIVec {
data: self.as_mut_ptr(),
len: self.len(),
cap: self.capacity()
};
self.leak();
ret
}
}
impl<T> Drop for FFIVec<T> {
fn drop(&mut self) {
unsafe {
Vec::from_raw_parts(self.data, self.len, self.cap);
}
}
}
impl<T> FFIVec<T> {
fn with_vec_ref<R, F: for<'a> FnOnce(&'a Vec<T>) -> R>(
&self, f: F
) -> R {
let v = unsafe {
Vec::from_raw_parts(self.data, self.len, self.cap)
};
let ret = f(&v);
v.leak();
ret
}
// currently unused
// may be nice to have later, though
#[allow(unused)]
fn with_vec_mut_ref<R, F: for<'a> FnOnce(&'a mut Vec<T>) -> R>(
&mut self, f: F
) -> R {
let mut v = unsafe {
Vec::from_raw_parts(self.data, self.len, self.cap)
};
let ret = f(&mut v);
self.data = v.as_mut_ptr();
self.len = v.len();
self.cap = v.capacity();
v.leak();
ret
}
}
impl<T> Clone for FFIVec<T>
where
T: Clone
{
fn clone(&self) -> FFIVec<T> {
self.with_vec_ref(|v| v.clone().into_ffi())
}
}
// https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
#[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum FFIOpt<T> {
Some(T),
None
}
impl<T> IntoFFI<FFIOpt<T>> for Option<T> {
fn into_ffi(self) -> FFIOpt<T> {
match self {
Some(v) => FFIOpt::Some(v),
None => FFIOpt::None
}
}
}
// FIXME: We need to ensure we deal with memory properly - whether it's owned by the C++ side or the Rust side
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct RustHamster<'a> {
ptr: *const u8,
len: usize,
phantom: PhantomData<&'a u8>
}
impl<'a> IntoFFI<RustHamster<'a>> for &'a str {
fn into_ffi(self) -> RustHamster<'a> {
RustHamster {
ptr: self.as_ptr(),
len: self.len(),
phantom: PhantomData,
}
}
}
impl<'a> RustHamster<'a> {
pub fn as_str(&self) -> &'a str {
unsafe {
let slice: &'a [u8] = std::slice::from_raw_parts(self.ptr, self.len);
std::str::from_utf8_unchecked(slice)
}
}
}
// Note: copied from rustc_span
/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct InnerSpan {
pub start: usize,
pub end: usize,
}
/// The location and before/after width of a character whose width has changed from its source code
/// representation
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(C)]
pub struct InnerWidthMapping {
/// Index of the character in the source
pub position: usize,
/// The inner width in characters
pub before: usize,
/// The transformed width in characters
pub after: usize,
}
// TODO: Not needed for now?
// /// Whether the input string is a literal. If yes, it contains the inner width mappings.
// #[derive(Clone, PartialEq, Eq)]
// #[repr(C)]
// enum InputStringKind {
// NotALiteral,
// Literal {
// width_mappings: Vec<InnerWidthMapping>,
// },
// }
// TODO: Not needed for now?
// /// The type of format string that we are parsing.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(C)]
pub enum ParseMode {
/// A normal format string as per `format_args!`.
Format = 0,
/// An inline assembly template string for `asm!`.
InlineAsm,
}
/// A piece is a portion of the format string which represents the next part
/// to emit. These are emitted as a stream by the `Parser` class.
#[derive(Clone)]
#[repr(C)]
pub enum Piece<'a> {
/// A literal string which should directly be emitted
String(RustHamster<'a>),
/// This describes that formatting should process the next argument (as
/// specified inside) for emission.
// do we need a pointer here? we're doing big cloning anyway
NextArgument(Argument<'a>),
}
/// Representation of an argument specification.
#[derive(Clone)]
#[repr(C)]
pub struct Argument<'a> {
/// Where to find this argument
pub position: Position<'a>,
/// The span of the position indicator. Includes any whitespace in implicit
/// positions (`{ }`).
pub position_span: InnerSpan,
/// How to format the argument
pub format: FormatSpec<'a>,
}
/// Specification for the formatting of an argument in the format string.
#[derive(Clone)]
#[repr(C)]
pub struct FormatSpec<'a> {
/// Optionally specified character to fill alignment with.
pub fill: FFIOpt<char>,
/// Span of the optionally specified fill character.
pub fill_span: FFIOpt<InnerSpan>,
/// Optionally specified alignment.
pub align: Alignment,
/// The `+` or `-` flag.
pub sign: FFIOpt<Sign>,
/// The `#` flag.
pub alternate: bool,
/// The `0` flag.
pub zero_pad: bool,
/// The `x` or `X` flag. (Only for `Debug`.)
pub debug_hex: FFIOpt<DebugHex>,
/// The integer precision to use.
pub precision: Count<'a>,
/// The span of the precision formatting flag (for diagnostics).
pub precision_span: FFIOpt<InnerSpan>,
/// The string width requested for the resulting format.
pub width: Count<'a>,
/// The span of the width formatting flag (for diagnostics).
pub width_span: FFIOpt<InnerSpan>,
/// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although
/// it is required to be one word.
pub ty: RustHamster<'a>,
/// The span of the descriptor string (for diagnostics).
pub ty_span: FFIOpt<InnerSpan>,
}
/// Enum describing where an argument for a format can be located.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub enum Position<'a> {
/// The argument is implied to be located at an index
ArgumentImplicitlyIs(usize),
/// The argument is located at a specific index given in the format,
ArgumentIs(usize),
/// The argument has a name.
ArgumentNamed(RustHamster<'a>),
}
/// Enum of alignments which are supported.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub enum Alignment {
/// The value will be aligned to the left.
AlignLeft,
/// The value will be aligned to the right.
AlignRight,
/// The value will be aligned in the center.
AlignCenter,
/// The value will take on a default alignment.
AlignUnknown,
}
/// Enum for the sign flags.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub enum Sign {
/// The `+` flag.
Plus,
/// The `-` flag.
Minus,
}
/// Enum for the debug hex flags.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub enum DebugHex {
/// The `x` flag in `{:x?}`.
Lower,
/// The `X` flag in `{:X?}`.
Upper,
}
/// A count is used for the precision and width parameters of an integer, and
/// can reference either an argument or a literal integer.
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub enum Count<'a> {
/// The count is specified explicitly.
CountIs(usize),
/// The count is specified by the argument with the given name.
CountIsName(RustHamster<'a>, InnerSpan),
/// The count is specified by the argument at the given index.
CountIsParam(usize),
/// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
CountIsStar(usize),
/// The count is implied and cannot be explicitly specified.
CountImplied,
}
impl<'a> From<generic_format_parser::Piece<'a>> for Piece<'a> {
fn from(old: generic_format_parser::Piece<'a>) -> Self {
match old {
generic_format_parser::Piece::String(x) => Piece::String(x.into_ffi()),
generic_format_parser::Piece::NextArgument(x) => {
// FIXME: This is problematic - if we do this, then we probably run into the issue that the Box
// is freed at the end of the call to collect_pieces. if we just .leak() it, then we have
// a memory leak... should we resend the info back to the Rust lib afterwards to free it?
// this is definitely the best way - store that pointer in the FFI piece and rebuild the box
// in a Rust destructor
let ptr = Box::leak(x);
let dst = Into::<Argument>::into(*ptr);
Piece::NextArgument(dst)
}
}
}
}
impl<'a> From<generic_format_parser::Argument<'a>> for Argument<'a> {
fn from(old: generic_format_parser::Argument<'a>) -> Self {
Argument {
position: old.position.into(),
position_span: old.position_span.into(),
format: old.format.into(),
}
}
}
impl<'a> From<generic_format_parser::Position<'a>> for Position<'a> {
fn from(old: generic_format_parser::Position<'a>) -> Self {
match old {
generic_format_parser::Position::ArgumentImplicitlyIs(x) => {
Position::ArgumentImplicitlyIs(x.into())
}
generic_format_parser::Position::ArgumentIs(x) => Position::ArgumentIs(x.into()),
generic_format_parser::Position::ArgumentNamed(x) => {
Position::ArgumentNamed(x.into_ffi())
}
}
}
}
impl From<generic_format_parser::InnerSpan> for InnerSpan {
fn from(old: generic_format_parser::InnerSpan) -> Self {
InnerSpan {
start: old.start,
end: old.end,
}
}
}
impl<'a> From<generic_format_parser::FormatSpec<'a>> for FormatSpec<'a> {
fn from(old: generic_format_parser::FormatSpec<'a>) -> Self {
FormatSpec {
fill: old.fill.into_ffi(),
fill_span: old.fill_span.map(Into::into).into_ffi(),
align: old.align.into(),
sign: old.sign.map(Into::into).into_ffi(),
alternate: old.alternate,
zero_pad: old.zero_pad,
debug_hex: old.debug_hex.map(Into::into).into_ffi(),
precision: old.precision.into(),
precision_span: old.precision_span.map(Into::into).into_ffi(),
width: old.width.into(),
width_span: old.width_span.map(Into::into).into_ffi(),
ty: old.ty.into_ffi(),
ty_span: old.ty_span.map(Into::into).into_ffi(),
}
}
}
impl From<generic_format_parser::DebugHex> for DebugHex {
fn from(old: generic_format_parser::DebugHex) -> Self {
match old {
generic_format_parser::DebugHex::Lower => DebugHex::Lower,
generic_format_parser::DebugHex::Upper => DebugHex::Upper,
}
}
}
impl<'a> From<generic_format_parser::Count<'a>> for Count<'a> {
fn from(old: generic_format_parser::Count<'a>) -> Self {
match old {
generic_format_parser::Count::CountIs(x) => Count::CountIs(x),
generic_format_parser::Count::CountIsName(x, y) => Count::CountIsName(x.into_ffi(), y.into()),
generic_format_parser::Count::CountIsParam(x) => Count::CountIsParam(x),
generic_format_parser::Count::CountIsStar(x) => Count::CountIsStar(x),
generic_format_parser::Count::CountImplied => Count::CountImplied,
}
}
}
impl From<generic_format_parser::Sign> for Sign {
fn from(old: generic_format_parser::Sign) -> Self {
match old {
generic_format_parser::Sign::Plus => Sign::Plus,
generic_format_parser::Sign::Minus => Sign::Minus,
}
}
}
impl From<generic_format_parser::Alignment> for Alignment {
fn from(old: generic_format_parser::Alignment) -> Self {
match old {
generic_format_parser::Alignment::AlignLeft => Alignment::AlignLeft,
generic_format_parser::Alignment::AlignRight => Alignment::AlignRight,
generic_format_parser::Alignment::AlignCenter => Alignment::AlignCenter,
generic_format_parser::Alignment::AlignUnknown => Alignment::AlignUnknown,
}
}
}
}
// FIXME: Rename?
pub mod rust {
use crate::ffi::ParseMode;
use generic_format_parser::{Parser, Piece};
pub fn collect_pieces(
input: &str,
style: Option<usize>,
snippet: Option<String>,
append_newline: bool,
parse_mode: ParseMode,
) -> Vec<Piece<'_>> {
let converted_parse_mode = match parse_mode {
ParseMode::Format => generic_format_parser::ParseMode::Format,
ParseMode::InlineAsm => generic_format_parser::ParseMode::InlineAsm,
};
let parser = Parser::new(input, style, snippet, append_newline, converted_parse_mode);
parser.into_iter().collect()
}
}
// TODO: Should we instead make an FFIVector struct?
type PieceVec<'a> = ffi::FFIVec<ffi::Piece<'a>>;
#[no_mangle]
pub extern "C" fn collect_pieces<'a>(
input: ffi::RustHamster<'a>,
append_newline: bool,
parse_mode: crate::ffi::ParseMode,
) -> PieceVec<'a> {
// FIXME: No unwrap
let pieces: Vec<ffi::Piece<'_>> =
rust::collect_pieces(input.as_str(), None, None, append_newline, parse_mode)
.into_iter()
.map(Into::into)
.collect();
pieces.into_ffi()
}
#[no_mangle]
pub extern "C" fn clone_pieces<'a, 'b>(
piece_vec: &'a PieceVec<'b>
) -> PieceVec<'b> {
piece_vec.clone()
}
// we need Layout::repeat
// function signature is a bit different, so call it repeat_x
trait LayoutExt {
fn repeat_x(&self, n: usize) -> Layout;
}
impl LayoutExt for Layout {
fn repeat_x(&self, n: usize) -> Layout {
let elem = self.pad_to_align();
let total_size = elem.size().checked_mul(n).unwrap();
Layout::from_size_align(total_size, elem.align()).unwrap()
}
}
#[no_mangle]
pub unsafe extern "C" fn rust_ffi_alloc(
count: usize, elem_size: usize, align: usize
) -> *mut u8 {
unsafe {
std::alloc::alloc(
Layout::from_size_align_unchecked(elem_size, align)
.repeat_x(count)
)
}
}
#[no_mangle]
pub unsafe extern "C" fn rust_ffi_dealloc(
data: *mut u8, count: usize, elem_size: usize, align: usize
) {
unsafe {
std::alloc::dealloc(
data,
Layout::from_size_align_unchecked(elem_size, align)
.repeat_x(count)
)
}
}