#![deny(missing_docs)]
mod sys;
pub use self::sys::types::{Net, Node, State};
use self::sys::functions::*;
pub struct SimulatedNet {
net: Box<Net>,
states: Vec<State<'static>>,
}
impl std::ops::Deref for SimulatedNet {
type Target = Net;
fn deref(&self) -> &Net {
&self.net
}
}
impl State<'_> {
pub fn added_transitions(&mut self, forward: bool) -> Box<[u32]> {
unsafe {
let mut count = std::mem::uninitialized();
pnsState_addedTransitions(self, &mut count, std::ptr::null_mut(), forward);
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
pnsState_addedTransitions(self, &mut count, transitions.as_mut_ptr(), forward);
transitions.into_boxed_slice()
}
}
pub fn removed_transitions(&mut self, forward: bool) -> Box<[u32]> {
unsafe {
let mut count = std::mem::uninitialized();
pnsState_removedTransitions(self, &mut count, std::ptr::null_mut(), forward);
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
pnsState_removedTransitions(self, &mut count, transitions.as_mut_ptr(), forward);
transitions.into_boxed_slice()
}
}
}
pub enum DynamicNet {
Default(Net),
Simulated(SimulatedNet),
}
pub trait SafeNet {
fn save(&self, filename: &str) -> bool;
fn transitions(&self) -> &[Node];
fn places(&self) -> &[Node];
fn initial_token_counts(&self) -> &[u32];
fn add_place(&mut self) -> u32;
fn add_transition(&mut self) -> u32;
fn add_connected_transition(&mut self, pids: &[u32]) -> u32;
fn remove_place(&mut self, pid: u32);
fn connect_out(&mut self, tid: u32, pid: u32) -> bool;
fn disconnect_in(&mut self, tid: u32, pid: u32);
fn duplicate_transition(&mut self, tid: u32) -> u32;
fn duplicate_place(&mut self, pid: u32) -> u32;
fn start(&mut self, pid: u32, count: u32) -> u32;
fn dynamic(self) -> DynamicNet;
}
impl DynamicNet {
pub fn default(&self) -> Option<&Net> {
if let DynamicNet::Default(net) = self {
Some(net)
} else {
None
}
}
pub fn default_mut(&mut self) -> Option<&mut Net> {
if let DynamicNet::Default(net) = self {
Some(net)
} else {
None
}
}
pub fn simulated(&self) -> Option<&SimulatedNet> {
if let DynamicNet::Simulated(net) = self {
Some(net)
} else {
None
}
}
pub fn simulated_mut(&mut self) -> Option<&mut SimulatedNet> {
if let DynamicNet::Simulated(net) = self {
Some(net)
} else {
None
}
}
pub fn safe(&self) -> &dyn SafeNet {
match self {
DynamicNet::Default(net) => net,
DynamicNet::Simulated(net) => net,
}
}
pub fn safe_mut(&mut self) -> &mut dyn SafeNet {
match self {
DynamicNet::Default(net) => net,
DynamicNet::Simulated(net) => net,
}
}
}
impl SimulatedNet {
pub fn new(net: Net) -> SimulatedNet {
let mut net = net;
unsafe { pnsNet_clearEdits(&mut net) }
SimulatedNet {
net: Box::new(net),
states: Vec::new(),
}
}
pub fn with_ref<'net, F: FnMut(&'net Net, &Vec<State<'net>>)>(&self, mut f: F)
where
Self: 'net,
{
unsafe {
let net = std::mem::transmute::<_, &&Net>(&self.net);
let states = std::mem::transmute(&self.states);
f(*net, states)
}
}
pub fn with<'net, F: FnMut(&'net Net, &mut Vec<State<'net>>)>(&mut self, mut f: F)
where
Self: 'net,
{
unsafe {
let net = std::mem::transmute::<_, &&Net>(&self.net);
let states = std::mem::transmute(&mut self.states);
f(*net, states)
}
}
pub fn add<'net, F: FnMut(&'net Net) -> State<'net>>(&mut self, mut f: F)
where
Self: 'net,
{
unsafe {
let net = std::mem::transmute::<_, &&Net>(&self.net);
self.states.push(std::mem::transmute(f(*net)));
}
}
pub fn add_state<'net>(&mut self)
where
Self: 'net,
{
self.add(|net| State::new(net));
}
pub fn len(&self) -> usize {
self.states.len()
}
pub fn states<'net>(&'net self) -> &[State<'net>] {
unsafe { std::mem::transmute(&self.states[..]) }
}
pub fn states_mut<'net>(&'net mut self) -> &mut [State<'net>] {
unsafe { std::mem::transmute(&mut self.states[..]) }
}
pub fn release(self) -> Net {
*self.net
}
fn update_states(&mut self) {
for state in &mut self.states {
unsafe {
pnsState_updateEdits(state);
}
}
unsafe { pnsNet_clearEdits(&mut *self.net) }
}
}
impl SafeNet for SimulatedNet {
#[inline]
fn save(&self, filename: &str) -> bool {
self.net.save(filename)
}
#[inline]
fn transitions(&self) -> &[Node] {
self.net.transitions()
}
#[inline]
fn places(&self) -> &[Node] {
self.net.places()
}
#[inline]
fn initial_token_counts(&self) -> &[u32] {
self.net.initial_token_counts()
}
#[inline]
fn add_place(&mut self) -> u32 {
let result = self.net.add_place();;
self.update_states();
result
}
#[inline]
fn add_transition(&mut self) -> u32 {
let result = self.net.add_transition();
self.update_states();
result
}
#[inline]
fn add_connected_transition(&mut self, pids: &[u32]) -> u32 {
let result = self.net.add_connected_transition(pids);
self.update_states();
result
}
#[inline]
fn remove_place(&mut self, pid: u32) {
let result = self.net.remove_place(pid);
self.update_states();
result
}
#[inline]
fn connect_out(&mut self, tid: u32, pid: u32) -> bool {
let result = self.net.connect_out(tid, pid);
self.update_states();
result
}
#[inline]
fn disconnect_in(&mut self, tid: u32, pid: u32) {
let result = self.net.disconnect_in(tid, pid);
self.update_states();
result
}
#[inline]
fn duplicate_transition(&mut self, tid: u32) -> u32 {
let result = self.net.duplicate_transition(tid);
self.update_states();
result
}
#[inline]
fn duplicate_place(&mut self, pid: u32) -> u32 {
let result = self.net.duplicate_place(pid);
self.update_states();
result
}
#[inline]
fn start(&mut self, pid: u32, count: u32) -> u32 {
let result = self.net.start(pid, count);
self.update_states();
result
}
fn dynamic(self) -> DynamicNet {
DynamicNet::Simulated(self)
}
}
use std::ffi::CString;
impl Node {
pub fn next(&self) -> &[u32] {
unsafe { std::slice::from_raw_parts(self.next, self.next_count as usize) }
}
pub fn prev(&self) -> &[u32] {
unsafe { std::slice::from_raw_parts(self.prev, self.prev_count as usize) }
}
}
impl Net {
pub fn new() -> Net {
unsafe {
let mut net = std::mem::uninitialized();
pnsCreateNet(&mut net);
net
}
}
pub fn load(filename: &str) -> Option<Net> {
unsafe {
let mut net: Net = std::mem::uninitialized();
if pnsLoadNet(&mut net, CString::new(filename).unwrap().as_ptr()) {
Some(net)
} else {
std::mem::forget(net);
None
}
}
}
pub fn remove_transition(&mut self, tid: u32) {
assert!(tid < self.transition_count, "Transition id out of range");
unsafe { pnsNet_removeTransition_unsafe(self, tid) }
}
pub fn connect_in(&mut self, tid: u32, pid: u32) -> bool {
assert!(tid < self.transition_count, "Transition id out of range");
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_connectIn_unsafe(self, tid, pid) }
}
pub fn disconnect_out(&mut self, tid: u32, pid: u32) {
assert!(tid < self.transition_count, "Transition id out of range");
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_disconnectOut_unsafe(self, tid, pid) }
}
}
impl SafeNet for Net {
fn save(&self, filename: &str) -> bool {
unsafe { pnsNet_save(self, CString::new(filename).unwrap().as_ptr()) }
}
fn transitions(&self) -> &[Node] {
unsafe { std::slice::from_raw_parts(self.transitions, self.transition_count as usize) }
}
fn places(&self) -> &[Node] {
unsafe { std::slice::from_raw_parts(self.places, self.place_count as usize) }
}
fn initial_token_counts(&self) -> &[u32] {
unsafe { std::slice::from_raw_parts(self.initial_token_counts, self.place_count as usize) }
}
fn add_place(&mut self) -> u32 {
unsafe { pnsNet_addPlace(self) }
}
fn add_transition(&mut self) -> u32 {
unsafe { pnsNet_addTransition(self) }
}
fn add_connected_transition(&mut self, pids: &[u32]) -> u32 {
for pid in pids {
assert!(*pid < self.place_count, "Place id out of range");
}
unsafe { pnsNet_addConnectedTransition(self, pids.len() as u32, pids.as_ptr()) }
}
fn remove_place(&mut self, pid: u32) {
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_removePlace(self, pid) }
}
fn connect_out(&mut self, tid: u32, pid: u32) -> bool {
assert!(tid < self.transition_count, "Transition id out of range");
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_connectOut(self, tid, pid) }
}
fn disconnect_in(&mut self, tid: u32, pid: u32) {
assert!(tid < self.transition_count, "Transition id out of range");
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_disconnectIn(self, tid, pid) }
}
fn duplicate_transition(&mut self, tid: u32) -> u32 {
assert!(tid < self.transition_count, "Transition id out of range");
unsafe { pnsNet_duplicateTransition(self, tid) }
}
fn duplicate_place(&mut self, pid: u32) -> u32 {
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_duplicatePlace(self, pid) }
}
fn start(&mut self, pid: u32, count: u32) -> u32 {
assert!(pid < self.place_count, "Place id out of range");
unsafe { pnsNet_start(self, pid, count) }
}
fn dynamic(self) -> DynamicNet {
DynamicNet::Default(self)
}
}
impl Clone for Net {
fn clone(&self) -> Self {
unsafe {
let mut net = std::mem::uninitialized();
pnsCloneNet(&mut net, self);
net
}
}
}
impl Drop for Net {
fn drop(&mut self) {
unsafe {
pnsDestroyNet(self);
}
}
}
impl<'net> State<'net> {
pub fn new(net: &'net Net) -> State<'net> {
unsafe {
let mut state = std::mem::MaybeUninit::uninit();
pnsCreateState(state.as_mut_ptr(), net);
state.assume_init()
}
}
pub fn load(net: &'net Net, filename: &str) -> Option<State<'net>> {
unsafe {
let mut state = std::mem::MaybeUninit::uninit();
if pnsLoadState(
state.as_mut_ptr(),
net,
CString::new(filename).unwrap().as_ptr(),
) {
Some(state.assume_init())
} else {
None
}
}
}
pub fn save(&self, filename: &str) -> bool {
unsafe { pnsState_save(self, CString::new(filename).unwrap().as_ptr()) }
}
pub fn call_counts(&self) -> &[u32] {
unsafe { std::slice::from_raw_parts(self.call_counts, self.net.transition_count as usize) }
}
pub fn token_counts(&self) -> &[u32] {
unsafe { std::slice::from_raw_parts(self.token_counts, self.net.place_count as usize) }
}
pub fn fire<'state>(&'state mut self) -> FireState<'net, 'state> {
FireState::new(self)
}
pub unsafe fn fire_unchecked(&mut self, tid: u32) {
pnsState_fire(self, tid);
}
pub fn reverse(&mut self) -> bool {
unsafe { pnsState_reverse(self) }
}
}
impl Clone for State<'_> {
fn clone(&self) -> Self {
unsafe {
let mut state = std::mem::MaybeUninit::uninit();
pnsCloneState(state.as_mut_ptr(), self);
state.assume_init()
}
}
}
impl Drop for State<'_> {
fn drop(&mut self) {
unsafe {
pnsDestroyState(self);
}
}
}
pub struct FireState<'net, 'state> {
state: &'state mut State<'net>,
pub transitions: Box<[u32]>,
}
impl<'net, 'state> FireState<'net, 'state> {
fn new(state: &'state mut State<'net>) -> Self {
unsafe {
let mut count = std::mem::uninitialized();
pnsState_transitions(state, &mut count, std::ptr::null_mut());
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
pnsState_transitions(state, &mut count, transitions.as_mut_ptr());
FireState {
state,
transitions: transitions.into_boxed_slice(),
}
}
}
pub fn finish(self, id: u32) {
unsafe {
pnsState_fire(self.state, self.transitions[id as usize]);
}
}
}