#![allow(non_camel_case_types)]
use std::convert::TryInto;
use std::sync::atomic::AtomicUsize;
use libc::c_char;
use crate::arena::Handle;
use crate::graph::File;
use crate::graph::InternedString;
use crate::graph::Node;
use crate::graph::NodeID;
use crate::graph::StackGraph;
use crate::graph::Symbol;
use crate::partial::PartialPath;
use crate::partial::PartialPathEdge;
use crate::partial::PartialPathEdgeList;
use crate::partial::PartialPaths;
use crate::partial::PartialScopeStack;
use crate::partial::PartialScopedSymbol;
use crate::partial::PartialSymbolStack;
use crate::stitching::Database;
use crate::stitching::DatabaseCandidates;
use crate::stitching::ForwardPartialPathStitcher;
use crate::stitching::GraphEdgeCandidates;
use crate::stitching::StitcherConfig;
use crate::CancellationError;
use crate::CancellationFlag;
pub struct sg_stack_graph {
pub inner: StackGraph,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_new() -> *mut sg_stack_graph {
Box::into_raw(Box::new(sg_stack_graph {
inner: StackGraph::new(),
}))
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_free(graph: *mut sg_stack_graph) {
drop(unsafe { Box::from_raw(graph) })
}
pub struct sg_partial_path_arena {
pub inner: PartialPaths,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_new() -> *mut sg_partial_path_arena {
Box::into_raw(Box::new(sg_partial_path_arena {
inner: PartialPaths::new(),
}))
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_free(partials: *mut sg_partial_path_arena) {
drop(unsafe { Box::from_raw(partials) })
}
pub struct sg_partial_path_database {
pub inner: Database,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_new() -> *mut sg_partial_path_database {
Box::into_raw(Box::new(sg_partial_path_database {
inner: Database::new(),
}))
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_free(db: *mut sg_partial_path_database) {
drop(unsafe { Box::from_raw(db) })
}
pub const SG_NULL_HANDLE: u32 = 0;
pub const SG_LIST_EMPTY_HANDLE: u32 = 0xffffffff;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum sg_deque_direction {
SG_DEQUE_FORWARDS,
SG_DEQUE_BACKWARDS,
}
impl Default for sg_deque_direction {
fn default() -> sg_deque_direction {
sg_deque_direction::SG_DEQUE_FORWARDS
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_ensure_both_directions(
db: *mut sg_partial_path_database,
partials: *mut sg_partial_path_arena,
) {
let db = unsafe { &mut (*db).inner };
let partials = unsafe { &mut (*partials).inner };
db.ensure_both_directions(partials);
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_ensure_forwards(
db: *mut sg_partial_path_database,
partials: *mut sg_partial_path_arena,
) {
let db = unsafe { &mut (*db).inner };
let partials = unsafe { &mut (*partials).inner };
db.ensure_forwards(partials);
}
#[repr(C)]
pub struct sg_symbol {
pub symbol: *const c_char,
pub symbol_len: usize,
}
pub type sg_symbol_handle = u32;
#[repr(C)]
pub struct sg_symbols {
pub symbols: *const sg_symbol,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_symbols(graph: *const sg_stack_graph) -> sg_symbols {
let graph = unsafe { &(*graph).inner };
sg_symbols {
symbols: graph.symbols.as_ptr() as *const sg_symbol,
count: graph.symbols.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_add_symbols(
graph: *mut sg_stack_graph,
count: usize,
symbols: *const c_char,
lengths: *const usize,
handles_out: *mut sg_symbol_handle,
) {
let graph = unsafe { &mut (*graph).inner };
let mut symbols = symbols as *const u8;
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let handles_out = unsafe {
std::slice::from_raw_parts_mut(handles_out as *mut Option<Handle<Symbol>>, count)
};
for i in 0..count {
let symbol = unsafe { std::slice::from_raw_parts(symbols, lengths[i]) };
handles_out[i] = match std::str::from_utf8(symbol) {
Ok(symbol) => Some(graph.add_symbol(symbol)),
Err(_) => None,
};
unsafe { symbols = symbols.add(lengths[i]) };
}
}
#[repr(C)]
pub struct sg_string {
pub content: *const c_char,
pub length: usize,
}
pub type sg_string_handle = u32;
#[repr(C)]
pub struct sg_strings {
pub strings: *const sg_string,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_strings(graph: *const sg_stack_graph) -> sg_strings {
let graph = unsafe { &(*graph).inner };
sg_strings {
strings: graph.strings.as_ptr() as *const sg_string,
count: graph.strings.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_add_strings(
graph: *mut sg_stack_graph,
count: usize,
strings: *const c_char,
lengths: *const usize,
handles_out: *mut sg_string_handle,
) {
let graph = unsafe { &mut (*graph).inner };
let mut strings = strings as *const u8;
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let handles_out = unsafe {
std::slice::from_raw_parts_mut(handles_out as *mut Option<Handle<InternedString>>, count)
};
for i in 0..count {
let string = unsafe { std::slice::from_raw_parts(strings, lengths[i]) };
handles_out[i] = match std::str::from_utf8(string) {
Ok(string) => Some(graph.add_string(string)),
Err(_) => None,
};
unsafe { strings = strings.add(lengths[i]) };
}
}
#[repr(C)]
pub struct sg_file {
pub name: *const c_char,
pub name_len: usize,
}
pub type sg_file_handle = u32;
impl Into<Handle<File>> for sg_file_handle {
fn into(self) -> Handle<File> {
unsafe { std::mem::transmute(self) }
}
}
#[repr(C)]
pub struct sg_files {
pub files: *const sg_file,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_files(graph: *const sg_stack_graph) -> sg_files {
let graph = unsafe { &(*graph).inner };
sg_files {
files: graph.files.as_ptr() as *const sg_file,
count: graph.files.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_add_files(
graph: *mut sg_stack_graph,
count: usize,
files: *const c_char,
lengths: *const usize,
handles_out: *mut sg_file_handle,
) {
let graph = unsafe { &mut (*graph).inner };
let mut files = files as *const u8;
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let handles_out =
unsafe { std::slice::from_raw_parts_mut(handles_out as *mut Option<Handle<File>>, count) };
for i in 0..count {
let file = unsafe { std::slice::from_raw_parts(files, lengths[i]) };
handles_out[i] = match std::str::from_utf8(file) {
Ok(file) => Some(graph.get_or_create_file(file)),
Err(_) => None,
};
unsafe { files = files.add(lengths[i]) };
}
}
#[repr(C)]
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct sg_node_id {
pub file: sg_file_handle,
pub local_id: u32,
}
impl sg_node_id {
fn is_empty(self) -> bool {
self.file == 0 && self.local_id == 0
}
}
impl Into<NodeID> for sg_node_id {
fn into(self) -> NodeID {
unsafe { std::mem::transmute(self) }
}
}
pub const SG_ROOT_NODE_ID: u32 = 1;
pub const SG_JUMP_TO_NODE_ID: u32 = 2;
#[repr(C)]
#[derive(Clone)]
pub struct sg_node {
pub kind: sg_node_kind,
pub id: sg_node_id,
pub symbol: sg_symbol_handle,
pub scope: sg_node_id,
pub is_endpoint: bool,
}
impl Into<Node> for sg_node {
fn into(self) -> Node {
unsafe { std::mem::transmute(self) }
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub enum sg_node_kind {
SG_NODE_KIND_DROP_SCOPES,
SG_NODE_KIND_JUMP_TO,
SG_NODE_KIND_POP_SCOPED_SYMBOL,
SG_NODE_KIND_POP_SYMBOL,
SG_NODE_KIND_PUSH_SCOPED_SYMBOL,
SG_NODE_KIND_PUSH_SYMBOL,
SG_NODE_KIND_ROOT,
SG_NODE_KIND_SCOPE,
}
pub type sg_node_handle = u32;
impl Into<Handle<Node>> for sg_node_handle {
fn into(self) -> Handle<Node> {
unsafe { std::mem::transmute(self) }
}
}
pub const SG_ROOT_NODE_HANDLE: sg_node_handle = 1;
pub const SG_JUMP_TO_NODE_HANDLE: sg_node_handle = 2;
#[repr(C)]
pub struct sg_nodes {
pub nodes: *const sg_node,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_nodes(graph: *const sg_stack_graph) -> sg_nodes {
let graph = unsafe { &(*graph).inner };
sg_nodes {
nodes: graph.nodes.as_ptr() as *const sg_node,
count: graph.nodes.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_get_or_create_nodes(
graph: *mut sg_stack_graph,
count: usize,
nodes: *const sg_node,
handles_out: *mut sg_node_handle,
) {
let graph = unsafe { &mut (*graph).inner };
let nodes = unsafe { std::slice::from_raw_parts(nodes, count) };
let handles_out =
unsafe { std::slice::from_raw_parts_mut(handles_out as *mut Option<Handle<Node>>, count) };
for i in 0..count {
let node_id = nodes[i].id;
handles_out[i] = validate_node(graph, &nodes[i])
.map(|node| graph.get_or_create_node(node_id.into(), node));
}
}
fn validate_node_id(graph: &StackGraph, node_id: sg_node_id) -> Option<()> {
if node_id.file == 0 || node_id.file >= (graph.files.len() as u32) {
return None;
}
Some(())
}
fn validate_node(graph: &StackGraph, node: &sg_node) -> Option<Node> {
if matches!(
&node.kind,
sg_node_kind::SG_NODE_KIND_JUMP_TO | sg_node_kind::SG_NODE_KIND_ROOT
) {
return None;
}
validate_node_id(graph, node.id)?;
if (node.symbol != 0)
!= matches!(
&node.kind,
sg_node_kind::SG_NODE_KIND_POP_SCOPED_SYMBOL
| sg_node_kind::SG_NODE_KIND_POP_SYMBOL
| sg_node_kind::SG_NODE_KIND_PUSH_SCOPED_SYMBOL
| sg_node_kind::SG_NODE_KIND_PUSH_SYMBOL
)
{
return None;
}
if (node.scope.is_empty())
== matches!(&node.kind, sg_node_kind::SG_NODE_KIND_PUSH_SCOPED_SYMBOL)
{
return None;
}
Some(node.clone().into())
}
#[repr(C)]
pub struct sg_edge {
pub source: sg_node_handle,
pub sink: sg_node_handle,
pub precedence: i32,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_add_edges(
graph: *mut sg_stack_graph,
count: usize,
edges: *const sg_edge,
) {
let graph = unsafe { &mut (*graph).inner };
let edges = unsafe { std::slice::from_raw_parts(edges, count) };
for i in 0..count {
let source = unsafe { std::mem::transmute(edges[i].source) };
let sink = unsafe { std::mem::transmute(edges[i].sink) };
graph.add_edge(source, sink, edges[i].precedence);
}
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct sg_source_info {
pub span: sg_span,
pub syntax_type: sg_string_handle,
pub containing_line: sg_string_handle,
pub definiens_span: sg_span,
pub fully_qualified_name: sg_string_handle,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct sg_span {
pub start: sg_position,
pub end: sg_position,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct sg_position {
pub line: usize,
pub column: sg_offset,
pub containing_line: sg_utf8_bounds,
pub trimmed_line: sg_utf8_bounds,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct sg_offset {
pub utf8_offset: usize,
pub utf16_offset: usize,
pub grapheme_offset: usize,
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct sg_utf8_bounds {
pub start: usize,
pub end: usize,
}
#[repr(C)]
pub struct sg_source_infos {
pub infos: *const sg_source_info,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_source_infos(graph: *const sg_stack_graph) -> sg_source_infos {
let graph = unsafe { &(*graph).inner };
sg_source_infos {
infos: graph.source_info.as_ptr() as *const sg_source_info,
count: graph.source_info.len(),
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct sg_node_source_info {
pub node: sg_node_handle,
pub source_info: sg_source_info,
}
#[no_mangle]
pub extern "C" fn sg_stack_graph_add_source_infos(
graph: *mut sg_stack_graph,
count: usize,
infos: *const sg_node_source_info,
) {
let graph = unsafe { &mut (*graph).inner };
let infos = unsafe { std::slice::from_raw_parts(infos, count) };
for i in 0..count {
let node = unsafe { std::mem::transmute(infos[i].node) };
let info = graph.source_info_mut(node);
*info = unsafe { std::mem::transmute(infos[i].source_info) };
}
}
pub type sg_symbol_stack_variable = u32;
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct sg_partial_scoped_symbol {
pub symbol: sg_symbol_handle,
pub scopes: sg_partial_scope_stack,
}
impl Into<PartialScopedSymbol> for sg_partial_scoped_symbol {
fn into(self) -> PartialScopedSymbol {
unsafe { std::mem::transmute(self) }
}
}
#[repr(C)]
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct sg_partial_symbol_stack {
pub cells: sg_partial_symbol_stack_cell_handle,
pub direction: sg_deque_direction,
pub length: u32,
pub variable: sg_symbol_stack_variable,
}
impl From<PartialSymbolStack> for sg_partial_symbol_stack {
fn from(stack: PartialSymbolStack) -> sg_partial_symbol_stack {
unsafe { std::mem::transmute(stack) }
}
}
pub type sg_partial_symbol_stack_cell_handle = u32;
#[repr(C)]
pub struct sg_partial_symbol_stack_cell {
pub head: sg_partial_scoped_symbol,
pub tail: sg_partial_symbol_stack_cell_handle,
pub reversed: sg_partial_symbol_stack_cell_handle,
}
#[repr(C)]
pub struct sg_partial_symbol_stack_cells {
pub cells: *const sg_partial_symbol_stack_cell,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_partial_symbol_stack_cells(
partials: *const sg_partial_path_arena,
) -> sg_partial_symbol_stack_cells {
let partials = unsafe { &(*partials).inner };
sg_partial_symbol_stack_cells {
cells: partials.partial_symbol_stacks.as_ptr() as *const sg_partial_symbol_stack_cell,
count: partials.partial_symbol_stacks.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_add_partial_symbol_stacks(
partials: *mut sg_partial_path_arena,
count: usize,
mut symbols: *const sg_partial_scoped_symbol,
lengths: *const usize,
variables: *const sg_symbol_stack_variable,
out: *mut sg_partial_symbol_stack,
) {
let partials = unsafe { &mut (*partials).inner };
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let variables = unsafe { std::slice::from_raw_parts(variables, count) };
let out = unsafe { std::slice::from_raw_parts_mut(out, count) };
for i in 0..count {
let length = lengths[i];
let symbols_slice = unsafe { std::slice::from_raw_parts(symbols, length) };
let mut stack = if variables[i] == 0 {
PartialSymbolStack::empty()
} else {
PartialSymbolStack::from_variable(variables[i].try_into().unwrap())
};
for j in 0..length {
let symbol = symbols_slice[j].into();
stack.push_back(partials, symbol);
}
let _ = stack.iter(partials);
out[i] = stack.into();
unsafe { symbols = symbols.add(length) };
}
}
pub type sg_scope_stack_variable = u32;
#[repr(C)]
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct sg_partial_scope_stack {
pub cells: sg_partial_scope_stack_cell_handle,
pub direction: sg_deque_direction,
pub length: u32,
pub variable: sg_scope_stack_variable,
}
impl From<PartialScopeStack> for sg_partial_scope_stack {
fn from(stack: PartialScopeStack) -> sg_partial_scope_stack {
unsafe { std::mem::transmute(stack) }
}
}
pub type sg_partial_scope_stack_cell_handle = u32;
#[repr(C)]
pub struct sg_partial_scope_stack_cell {
pub head: sg_node_handle,
pub tail: sg_partial_scope_stack_cell_handle,
pub reversed: sg_partial_scope_stack_cell_handle,
}
#[repr(C)]
pub struct sg_partial_scope_stack_cells {
pub cells: *const sg_partial_scope_stack_cell,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_partial_scope_stack_cells(
partials: *const sg_partial_path_arena,
) -> sg_partial_scope_stack_cells {
let partials = unsafe { &(*partials).inner };
sg_partial_scope_stack_cells {
cells: partials.partial_scope_stacks.as_ptr() as *const sg_partial_scope_stack_cell,
count: partials.partial_scope_stacks.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_add_partial_scope_stacks(
partials: *mut sg_partial_path_arena,
count: usize,
mut scopes: *const sg_node_handle,
lengths: *const usize,
variables: *const sg_scope_stack_variable,
out: *mut sg_partial_scope_stack,
) {
let partials = unsafe { &mut (*partials).inner };
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let variables = unsafe { std::slice::from_raw_parts(variables, count) };
let out = unsafe { std::slice::from_raw_parts_mut(out, count) };
for i in 0..count {
let length = lengths[i];
let scopes_slice = unsafe { std::slice::from_raw_parts(scopes, length) };
let mut stack = if variables[i] == 0 {
PartialScopeStack::empty()
} else {
PartialScopeStack::from_variable(variables[i].try_into().unwrap())
};
for j in 0..length {
let node = scopes_slice[j].into();
stack.push_back(partials, node);
}
let _ = stack.iter_scopes(partials);
out[i] = stack.into();
unsafe { scopes = scopes.add(length) };
}
}
#[repr(C)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct sg_partial_path_edge {
pub source_node_id: sg_node_id,
pub precedence: i32,
}
impl Into<PartialPathEdge> for sg_partial_path_edge {
fn into(self) -> PartialPathEdge {
unsafe { std::mem::transmute(self) }
}
}
#[repr(C)]
#[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct sg_partial_path_edge_list {
pub cells: sg_partial_path_edge_list_cell_handle,
pub direction: sg_deque_direction,
pub length: u32,
}
impl From<PartialPathEdgeList> for sg_partial_path_edge_list {
fn from(edges: PartialPathEdgeList) -> sg_partial_path_edge_list {
unsafe { std::mem::transmute(edges) }
}
}
pub type sg_partial_path_edge_list_cell_handle = u32;
#[repr(C)]
pub struct sg_partial_path_edge_list_cell {
pub head: sg_partial_path_edge,
pub tail: sg_partial_path_edge_list_cell_handle,
pub reversed: sg_partial_path_edge_list_cell_handle,
}
#[repr(C)]
pub struct sg_partial_path_edge_list_cells {
pub cells: *const sg_partial_path_edge_list_cell,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_partial_path_edge_list_cells(
partials: *const sg_partial_path_arena,
) -> sg_partial_path_edge_list_cells {
let partials = unsafe { &(*partials).inner };
sg_partial_path_edge_list_cells {
cells: partials.partial_path_edges.as_ptr() as *const sg_partial_path_edge_list_cell,
count: partials.partial_path_edges.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_add_partial_path_edge_lists(
partials: *mut sg_partial_path_arena,
count: usize,
mut edges: *const sg_partial_path_edge,
lengths: *const usize,
out: *mut sg_partial_path_edge_list,
) {
let partials = unsafe { &mut (*partials).inner };
let lengths = unsafe { std::slice::from_raw_parts(lengths, count) };
let out = unsafe { std::slice::from_raw_parts_mut(out, count) };
for i in 0..count {
let length = lengths[i];
let edges_slice = unsafe { std::slice::from_raw_parts(edges, length) };
let mut list = PartialPathEdgeList::empty();
for j in 0..length {
let edge: PartialPathEdge = edges_slice[j].into();
list.push_back(partials, edge);
}
let _ = list.iter(partials);
out[i] = list.into();
unsafe { edges = edges.add(length) };
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct sg_partial_path {
pub start_node: sg_node_handle,
pub end_node: sg_node_handle,
pub symbol_stack_precondition: sg_partial_symbol_stack,
pub symbol_stack_postcondition: sg_partial_symbol_stack,
pub scope_stack_precondition: sg_partial_scope_stack,
pub scope_stack_postcondition: sg_partial_scope_stack,
pub edges: sg_partial_path_edge_list,
}
impl Into<PartialPath> for sg_partial_path {
fn into(self) -> PartialPath {
unsafe { std::mem::transmute(self) }
}
}
#[derive(Default)]
pub struct sg_partial_path_list {
partial_paths: Vec<PartialPath>,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_list_new() -> *mut sg_partial_path_list {
Box::into_raw(Box::new(sg_partial_path_list::default()))
}
#[no_mangle]
pub extern "C" fn sg_partial_path_list_free(partial_path_list: *mut sg_partial_path_list) {
drop(unsafe { Box::from_raw(partial_path_list) });
}
#[no_mangle]
pub extern "C" fn sg_partial_path_list_count(
partial_path_list: *const sg_partial_path_list,
) -> usize {
let partial_path_list = unsafe { &*partial_path_list };
partial_path_list.partial_paths.len()
}
#[no_mangle]
pub extern "C" fn sg_partial_path_list_paths(
partial_path_list: *const sg_partial_path_list,
) -> *const sg_partial_path {
let partial_path_list = unsafe { &*partial_path_list };
partial_path_list.partial_paths.as_ptr() as *const _
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_find_partial_paths_in_file(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
file: sg_file_handle,
partial_path_list: *mut sg_partial_path_list,
stitcher_config: *const sg_stitcher_config,
cancellation_flag: *const usize,
) -> sg_result {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let file = file.into();
let partial_path_list = unsafe { &mut *partial_path_list };
let stitcher_config = unsafe { *stitcher_config };
let cancellation_flag: Option<&AtomicUsize> =
unsafe { std::mem::transmute(cancellation_flag.as_ref()) };
ForwardPartialPathStitcher::find_minimal_partial_path_set_in_file(
graph,
partials,
file,
stitcher_config.into(),
&AtomicUsizeCancellationFlag(cancellation_flag),
|_graph, partials, path| {
let mut path = path.clone();
path.ensure_both_directions(partials);
partial_path_list.partial_paths.push(path);
},
)
.into()
}
#[no_mangle]
pub extern "C" fn sg_partial_path_arena_find_all_complete_paths(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
starting_node_count: usize,
starting_nodes: *const sg_node_handle,
path_list: *mut sg_partial_path_list,
stitcher_config: *const sg_stitcher_config,
cancellation_flag: *const usize,
) -> sg_result {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let starting_nodes = unsafe { std::slice::from_raw_parts(starting_nodes, starting_node_count) };
let stitcher_config = unsafe { *stitcher_config };
let path_list = unsafe { &mut *path_list };
let cancellation_flag: Option<&AtomicUsize> =
unsafe { std::mem::transmute(cancellation_flag.as_ref()) };
ForwardPartialPathStitcher::find_all_complete_partial_paths(
&mut GraphEdgeCandidates::new(graph, partials, None),
starting_nodes.iter().copied().map(sg_node_handle::into),
stitcher_config.into(),
&AtomicUsizeCancellationFlag(cancellation_flag),
|graph, _partials, path| {
if path.is_complete(graph) {
path_list.partial_paths.push(path.clone());
}
},
)
.into()
}
pub type sg_partial_path_handle = u32;
#[repr(C)]
pub struct sg_partial_paths {
pub paths: *const sg_partial_path,
pub count: usize,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_partial_paths(
db: *const sg_partial_path_database,
) -> sg_partial_paths {
let db = unsafe { &(*db).inner };
sg_partial_paths {
paths: db.partial_paths.as_ptr() as *const sg_partial_path,
count: db.partial_paths.len(),
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_add_partial_paths(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
db: *mut sg_partial_path_database,
count: usize,
paths: *const sg_partial_path,
out: *mut sg_partial_path_handle,
) {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let db = unsafe { &mut (*db).inner };
let paths = unsafe { std::slice::from_raw_parts(paths, count) };
let out = unsafe { std::slice::from_raw_parts_mut(out as *mut Handle<PartialPath>, count) };
for i in 0..count {
out[i] = db.add_partial_path(graph, partials, paths[i].into());
}
}
#[repr(C)]
pub struct sg_node_handle_set {
pub elements: *const u32,
pub length: usize,
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_find_local_nodes(db: *mut sg_partial_path_database) {
let db = unsafe { &mut (*db).inner };
db.find_local_nodes();
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_mark_local_nodes(
db: *mut sg_partial_path_database,
count: usize,
nodes: *const sg_node_handle,
) {
let db = unsafe { &mut (*db).inner };
let nodes = unsafe { std::slice::from_raw_parts(nodes, count) };
for node in nodes {
db.mark_local_node(node.clone().into());
}
}
#[no_mangle]
pub extern "C" fn sg_partial_path_database_local_nodes(
db: *const sg_partial_path_database,
) -> sg_node_handle_set {
let db = unsafe { &(*db).inner };
sg_node_handle_set {
elements: db.local_nodes.as_ptr(),
length: db.local_nodes.len(),
}
}
#[repr(C)]
pub struct sg_forward_partial_path_stitcher {
pub previous_phase_partial_paths: *const sg_partial_path,
pub previous_phase_partial_paths_length: usize,
pub is_complete: bool,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct sg_stitcher_config {
pub detect_similar_paths: bool,
}
impl Into<StitcherConfig> for sg_stitcher_config {
fn into(self) -> StitcherConfig {
StitcherConfig::default().with_detect_similar_paths(self.detect_similar_paths)
}
}
#[repr(C)]
struct InternalForwardPartialPathStitcher {
previous_phase_partial_paths: *const PartialPath,
previous_phase_partial_paths_length: usize,
is_complete: bool,
stitcher: ForwardPartialPathStitcher<Handle<PartialPath>>,
}
impl InternalForwardPartialPathStitcher {
fn new(
stitcher: ForwardPartialPathStitcher<Handle<PartialPath>>,
partials: &mut PartialPaths,
) -> InternalForwardPartialPathStitcher {
let mut this = InternalForwardPartialPathStitcher {
previous_phase_partial_paths: std::ptr::null(),
previous_phase_partial_paths_length: 0,
is_complete: false,
stitcher,
};
this.update_previous_phase_partial_paths(partials);
this
}
fn update_previous_phase_partial_paths(&mut self, partials: &mut PartialPaths) {
for path in self.stitcher.previous_phase_partial_paths_slice_mut() {
path.ensure_both_directions(partials);
}
let slice = self.stitcher.previous_phase_partial_paths_slice();
self.previous_phase_partial_paths = slice.as_ptr();
self.previous_phase_partial_paths_length = slice.len();
self.is_complete = self.stitcher.is_complete();
}
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_from_nodes(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
count: usize,
starting_nodes: *const sg_node_handle,
) -> *mut sg_forward_partial_path_stitcher {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let starting_nodes = unsafe { std::slice::from_raw_parts(starting_nodes, count) };
let initial_paths = starting_nodes
.iter()
.copied()
.map(sg_node_handle::into)
.map(|n| {
let mut p = PartialPath::from_node(graph, partials, n);
p.eliminate_precondition_stack_variables(partials);
p
})
.collect::<Vec<_>>();
let stitcher = ForwardPartialPathStitcher::from_partial_paths(graph, partials, initial_paths);
Box::into_raw(Box::new(InternalForwardPartialPathStitcher::new(
stitcher, partials,
))) as *mut _
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_from_partial_paths(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
count: usize,
initial_partial_paths: *const sg_partial_path,
) -> *mut sg_forward_partial_path_stitcher {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let initial_partial_paths =
unsafe { std::slice::from_raw_parts(initial_partial_paths as *const PartialPath, count) };
let stitcher = ForwardPartialPathStitcher::from_partial_paths(
graph,
partials,
initial_partial_paths.to_vec(),
);
Box::into_raw(Box::new(InternalForwardPartialPathStitcher::new(
stitcher, partials,
))) as *mut _
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_set_similar_path_detection(
stitcher: *mut sg_forward_partial_path_stitcher,
detect_similar_paths: bool,
) {
let stitcher = unsafe { &mut *(stitcher as *mut InternalForwardPartialPathStitcher) };
stitcher
.stitcher
.set_similar_path_detection(detect_similar_paths);
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_set_max_work_per_phase(
stitcher: *mut sg_forward_partial_path_stitcher,
max_work: usize,
) {
let stitcher = unsafe { &mut *(stitcher as *mut InternalForwardPartialPathStitcher) };
stitcher.stitcher.set_max_work_per_phase(max_work);
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_process_next_phase(
graph: *const sg_stack_graph,
partials: *mut sg_partial_path_arena,
db: *mut sg_partial_path_database,
stitcher: *mut sg_forward_partial_path_stitcher,
) {
let graph = unsafe { &(*graph).inner };
let partials = unsafe { &mut (*partials).inner };
let db = unsafe { &mut (*db).inner };
let stitcher = unsafe { &mut *(stitcher as *mut InternalForwardPartialPathStitcher) };
stitcher.stitcher.process_next_phase(
&mut DatabaseCandidates::new(graph, partials, db),
|_, _, _| true,
);
stitcher.update_previous_phase_partial_paths(partials);
}
#[no_mangle]
pub extern "C" fn sg_forward_partial_path_stitcher_free(
stitcher: *mut sg_forward_partial_path_stitcher,
) {
drop(unsafe { Box::from_raw(stitcher as *mut InternalForwardPartialPathStitcher) });
}
struct AtomicUsizeCancellationFlag<'a>(Option<&'a AtomicUsize>);
impl CancellationFlag for AtomicUsizeCancellationFlag<'_> {
fn check(&self, at: &'static str) -> Result<(), crate::CancellationError> {
self.0
.map(|flag| {
if flag.fetch_and(0b0, std::sync::atomic::Ordering::Relaxed) != 0 {
Err(CancellationError(at))
} else {
Ok(())
}
})
.unwrap_or(Ok(()))
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum sg_result {
SG_RESULT_SUCCESS,
SG_RESULT_CANCELLED,
}
impl<T> From<Result<T, CancellationError>> for sg_result {
fn from(result: Result<T, CancellationError>) -> Self {
match result {
Ok(_) => Self::SG_RESULT_SUCCESS,
Err(_) => Self::SG_RESULT_CANCELLED,
}
}
}