#![deny(missing_docs)]
mod sys;
pub use self::sys::types::{Net, Node, State};
use self::sys::functions::*;
pub struct SimulatedNet {
net: Net,
pub states: Vec<State>,
}
impl Clone for SimulatedNet {
fn clone(&self) -> Self {
let net = self.net.clone();
let mut states = Vec::new();
for old_state in &self.states {
states.push(unsafe {
let mut state = std::mem::MaybeUninit::uninit();
pnsCloneState(state.as_mut_ptr(), old_state, &net);
state.assume_init()
})
}
Self { net, states }
}
}
impl std::ops::Deref for SimulatedNet {
type Target = Net;
fn deref(&self) -> &Net {
&self.net
}
}
pub struct Iter<'net> {
net: &'net Net,
states: std::slice::Iter<'net, State>,
}
pub struct IterMut<'net> {
net: &'net Net,
states: std::slice::IterMut<'net, State>,
}
pub struct SimulationState<'net> {
net: &'net Net,
pub state: &'net State,
}
pub struct SimulationStateMut<'net> {
net: &'net Net,
pub state: &'net mut State,
}
impl<'net> IntoIterator for &'net SimulatedNet {
type Item = SimulationState<'net>;
type IntoIter = Iter<'net>;
fn into_iter(self) -> Self::IntoIter {
Iter {
net: &self.net,
states: (&self.states).iter(),
}
}
}
impl<'net> IntoIterator for &'net mut SimulatedNet {
type Item = SimulationStateMut<'net>;
type IntoIter = IterMut<'net>;
fn into_iter(self) -> Self::IntoIter {
IterMut {
net: &self.net,
states: (&mut self.states).iter_mut(),
}
}
}
impl<'net> Iterator for Iter<'net> {
type Item = SimulationState<'net>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(state) = self.states.next() {
Some(SimulationState {
net: &self.net,
state,
})
} else {
None
}
}
}
impl<'net> Iterator for IterMut<'net> {
type Item = SimulationStateMut<'net>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(state) = self.states.next() {
Some(SimulationStateMut {
net: &self.net,
state,
})
} else {
None
}
}
}
pub enum DynamicNet {
Default(Net),
Simulated(SimulatedNet),
}
pub trait SafeNet {
fn save(&self, filename: &str) -> bool;
fn transitions(&self) -> &[Node];
fn reusable_transition(&self) -> Option<u32>;
fn places(&self) -> &[Node];
fn reusable_place(&self) -> Option<u32>;
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() -> SimulatedNet {
SimulatedNet {
net: Net::new(),
states: Vec::new(),
}
}
pub fn load(filename: &str) -> Option<SimulatedNet> {
Some(SimulatedNet {
net: Net::load(filename)?,
states: Vec::new(),
})
}
pub fn from_net(net: Net) -> SimulatedNet {
let mut net = net;
unsafe { pnsNet_clearEdits(&mut net) }
SimulatedNet {
net,
states: Vec::new(),
}
}
pub fn add_state(&mut self) {
let state = State::new(&self.net);
self.states.push(state);
}
#[must_use]
pub fn load_state(&mut self, filename: &str) -> Option<()> {
if let Some(state) = State::load(&self.net, filename) {
self.states.push(state);
Some(())
} else {
None
}
}
pub fn state<'net>(&'net self, index: usize) -> SimulationState<'net> {
SimulationState {
net: &self.net,
state: &self.states[index],
}
}
pub fn state_mut<'net>(&'net mut self, index: usize) -> SimulationStateMut<'net> {
SimulationStateMut {
net: &self.net,
state: &mut self.states[index],
}
}
pub fn len(&self) -> usize {
self.states.len()
}
pub fn release(self) -> Net {
self.net
}
fn update_states(&mut self) {
for state in &mut self.states {
unsafe {
pnsState_updateEdits(state, &self.net);
}
}
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 reusable_transition(&self) -> Option<u32> {
self.net.reusable_transition()
}
#[inline]
fn places(&self) -> &[Node] {
self.net.places()
}
#[inline]
fn reusable_place(&self) -> Option<u32> {
self.net.reusable_place()
}
#[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::MaybeUninit::uninit();
pnsCreateNet(net.as_mut_ptr());
net.assume_init()
}
}
pub fn load(filename: &str) -> Option<Net> {
unsafe {
let mut net = std::mem::MaybeUninit::uninit();
if pnsLoadNet(net.as_mut_ptr(), CString::new(filename).unwrap().as_ptr()) {
Some(net.assume_init())
} else {
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 reusable_transition(&self) -> Option<u32> {
if let Some(list) = unsafe { self.reusable_transitions.as_ref() } {
Some(list.index)
} else {
None
}
}
fn places(&self) -> &[Node] {
unsafe { std::slice::from_raw_parts(self.places, self.place_count as usize) }
}
fn reusable_place(&self) -> Option<u32> {
if let Some(list) = unsafe { self.reusable_places.as_ref() } {
Some(list.index)
} else {
None
}
}
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::MaybeUninit::uninit();
pnsCloneNet(net.as_mut_ptr(), self);
net.assume_init()
}
}
}
impl Drop for Net {
fn drop(&mut self) {
unsafe {
pnsDestroyNet(self);
}
}
}
impl State {
fn new(net: &Net) -> State {
unsafe {
let mut state = std::mem::MaybeUninit::uninit();
pnsCreateState(state.as_mut_ptr(), net);
state.assume_init()
}
}
fn load(net: &Net, filename: &str) -> Option<State> {
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
}
}
}
fn changed_transitions(
&mut self,
call: unsafe extern "C" fn(state: *mut State, *mut u32, *mut u32),
) -> Box<[u32]> {
unsafe {
let mut count = std::mem::MaybeUninit::uninit();
call(self, count.as_mut_ptr(), std::ptr::null_mut());
let mut count = count.assume_init();
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
call(self, &mut count, transitions.as_mut_ptr());
transitions.into_boxed_slice()
}
}
pub fn added_transitions(&mut self) -> Box<[u32]> {
self.changed_transitions(pnsState_addedTransitions)
}
pub fn added_transitions_backwards(&mut self) -> Box<[u32]> {
self.changed_transitions(pnsState_addedTransitions_backwards)
}
pub fn removed_transitions(&mut self) -> Box<[u32]> {
self.changed_transitions(pnsState_removedTransitions)
}
pub fn removed_transitions_backwards(&mut self) -> Box<[u32]> {
self.changed_transitions(pnsState_removedTransitions_backwards)
}
}
impl Drop for State {
fn drop(&mut self) {
unsafe {
pnsDestroyState(self);
}
}
}
impl<'net> SimulationState<'net> {
pub fn save(&self, filename: &str) -> bool {
let path = CString::new(filename).unwrap().as_ptr();
unsafe { pnsState_save(self.state, self.net, path) }
}
pub fn call_counts(&self) -> &[u32] {
unsafe {
std::slice::from_raw_parts(self.state.call_counts, self.net.transition_count as usize)
}
}
pub fn token_counts(&self) -> &[u32] {
unsafe {
std::slice::from_raw_parts(self.state.token_counts, self.net.place_count as usize)
}
}
}
impl<'net> SimulationStateMut<'net> {
pub fn save(&self, filename: &str) -> bool {
let path = CString::new(filename).unwrap().as_ptr();
unsafe { pnsState_save(self.state, self.net, path) }
}
pub fn call_counts(&self) -> &[u32] {
unsafe {
std::slice::from_raw_parts(self.state.call_counts, self.net.transition_count as usize)
}
}
pub fn token_counts(&self) -> &[u32] {
unsafe {
std::slice::from_raw_parts(self.state.token_counts, self.net.place_count as usize)
}
}
pub fn fire<'state>(&'state mut self) -> FireState<'net, 'state> {
FireState::new(self)
}
pub fn unfire<'state>(&'state mut self) -> FireState<'net, 'state> {
FireState::new_backwards(self)
}
pub unsafe fn fire_unchecked(&mut self, tid: u32) {
pnsState_fire(self.state, self.net, tid);
}
pub unsafe fn unfire_unchecked(&mut self, tid: u32) {
pnsState_fire_backwards(self.state, self.net, tid);
}
}
pub struct FireState<'net, 'state> {
state: &'state mut SimulationStateMut<'net>,
pub transitions: Box<[u32]>,
backwards: bool,
}
impl<'net, 'state> FireState<'net, 'state> {
fn new(state: &'state mut SimulationStateMut<'net>) -> Self {
unsafe {
let mut count = std::mem::MaybeUninit::uninit();
pnsState_transitions(state.state, count.as_mut_ptr(), std::ptr::null_mut());
let mut count = count.assume_init();
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
pnsState_transitions(state.state, &mut count, transitions.as_mut_ptr());
FireState {
state,
transitions: transitions.into_boxed_slice(),
backwards: false,
}
}
}
fn new_backwards(state: &'state mut SimulationStateMut<'net>) -> Self {
unsafe {
let mut count = std::mem::MaybeUninit::uninit();
pnsState_transitions_backwards(state.state, count.as_mut_ptr(), std::ptr::null_mut());
let mut count = count.assume_init();
let mut transitions = Vec::with_capacity(count as usize);
transitions.set_len(count as usize);
pnsState_transitions_backwards(state.state, &mut count, transitions.as_mut_ptr());
FireState {
state,
transitions: transitions.into_boxed_slice(),
backwards: true,
}
}
}
pub fn finish(self, id: u32) {
if self.backwards {
unsafe {
pnsState_fire_backwards(
self.state.state,
self.state.net,
self.transitions[id as usize],
);
}
} else {
unsafe {
pnsState_fire(
self.state.state,
self.state.net,
self.transitions[id as usize],
);
}
}
}
}