use std::{
fs::File,
io::{Error, ErrorKind, Write},
marker::PhantomData,
mem::MaybeUninit,
path::Path,
};
use crate::{
core::{
ids::{Ids, Pid, Place, Tid, Transition},
utils::read_values,
},
sys::{
functions::net::*,
types::{Net, Node},
},
};
impl Net {
pub fn new() -> Self {
unsafe {
let mut net = MaybeUninit::uninit();
pnsCreateNet(net.as_mut_ptr());
net.assume_init()
}
}
pub fn load(filename: &Path) -> Result<Self, Error> {
let values = read_values(filename)?;
unsafe {
let mut net = MaybeUninit::uninit();
if pnsLoadNet(net.as_mut_ptr(), values.len(), &raw const values[0]) {
Ok(net.assume_init())
} else {
Err(Error::new(
ErrorKind::InvalidData,
"File does not represent a petri net",
))
}
}
}
pub fn save(&self, filename: &Path) -> Result<(), Error> {
let mut file = File::create(filename)?;
let data = unsafe {
let count = pnsNet_serializeSize(self);
let mut data = vec![0u32; count];
pnsNet_serialize(self, &raw mut data[0]);
data
};
for value in data {
file.write_all(&value.to_le_bytes())?;
}
Ok(())
}
pub fn transition_count(&self) -> usize {
self.transitions.count
}
pub fn transition_ids(&self) -> Ids<Transition> {
Ids {
start: 0,
end: self.transitions.count,
kind: PhantomData::<Transition>,
}
}
pub fn transition(&self, tid: Tid) -> &Node<Pid> {
unsafe {
&std::slice::from_raw_parts(self.transitions.nodes.cast(), self.transitions.count)
[tid.index]
}
}
pub fn reusable_transition(&self) -> Option<Tid> {
unsafe { self.transitions.reusable.as_ref() }.map(|list| Tid::new(list.index))
}
pub fn place_count(&self) -> usize {
self.places.count
}
pub fn place_ids(&self) -> Ids<Place> {
Ids {
start: 0,
end: self.places.count,
kind: PhantomData::<Place>,
}
}
pub fn place(&self, pid: Pid) -> &Node<Tid> {
unsafe {
&std::slice::from_raw_parts(self.places.nodes.cast(), self.places.count)[pid.index]
}
}
pub fn reusable_place(&self) -> Option<Pid> {
unsafe { self.places.reusable.as_ref() }.map(|list| Pid::new(list.index))
}
pub fn initial_token_count(&self, pid: Pid) -> usize {
unsafe {
std::slice::from_raw_parts(self.initial_token_counts, self.places.count)[pid.index]
}
}
pub fn add_place(&mut self) -> Pid {
unsafe { Pid::new(pnsNet_addPlace(self)) }
}
pub fn add_transition(&mut self) -> Tid {
unsafe { Tid::new(pnsNet_addTransition(self)) }
}
pub fn remove_place(&mut self, pid: Pid) {
pid.assert(self.places.count);
unsafe { pnsNet_removePlace(self, pid.index) }
}
pub fn remove_transition(&mut self, tid: Tid) {
tid.assert(self.transitions.count);
unsafe { pnsNet_removeTransition(self, tid.index) }
}
pub fn connect_place_to_transition(&mut self, pid: Pid, tid: Tid) -> bool {
tid.assert(self.transitions.count);
pid.assert(self.places.count);
unsafe { pnsNet_connectPlaceToTransition(self, pid.index, tid.index) }
}
pub fn connect_transition_to_place(&mut self, tid: Tid, pid: Pid) -> bool {
tid.assert(self.transitions.count);
pid.assert(self.places.count);
unsafe { pnsNet_connectTransitionToPlace(self, tid.index, pid.index) }
}
pub fn disconnect_place_to_transition(&mut self, pid: Pid, tid: Tid) {
tid.assert(self.transitions.count);
pid.assert(self.places.count);
unsafe { pnsNet_disconnectPlaceToTransition(self, pid.index, tid.index) }
}
pub fn disconnect_transition_to_place(&mut self, tid: Tid, pid: Pid) {
tid.assert(self.transitions.count);
pid.assert(self.places.count);
unsafe { pnsNet_disconnectTransitionToPlace(self, tid.index, pid.index) }
}
pub fn add_initial_tokens(&mut self, pid: Pid, count: usize) -> usize {
pid.assert(self.places.count);
unsafe { pnsNet_addInitialTokens(self, pid.index, count) }
}
pub fn add_connected_place(&mut self, in_tids: &[Tid], out_tids: &[Tid]) -> Pid {
for tid in in_tids.iter().chain(out_tids) {
tid.assert(self.transitions.count);
}
Pid::new(unsafe {
pnsNet_addConnectedPlace(
self,
in_tids.len(),
in_tids.as_ptr().cast(),
out_tids.len(),
out_tids.as_ptr().cast(),
)
})
}
pub fn add_connected_transition(&mut self, in_pids: &[Pid], out_pids: &[Pid]) -> Tid {
for pid in in_pids.iter().chain(out_pids) {
pid.assert(self.places.count);
}
Tid::new(unsafe {
pnsNet_addConnectedTransition(
self,
in_pids.len(),
in_pids.as_ptr().cast(),
out_pids.len(),
out_pids.as_ptr().cast(),
)
})
}
pub fn duplicate_place(&mut self, pid: Pid) -> Pid {
pid.assert(self.places.count);
Pid::new(unsafe { pnsNet_duplicatePlace(self, pid.index) })
}
pub fn duplicate_transition(&mut self, tid: Tid) -> Tid {
tid.assert(self.transitions.count);
Tid::new(unsafe { pnsNet_duplicateTransition(self, tid.index) })
}
}
impl Clone for Net {
fn clone(&self) -> Self {
unsafe {
let mut net = MaybeUninit::uninit();
pnsCloneNet(net.as_mut_ptr(), self);
net.assume_init()
}
}
}
impl Drop for Net {
fn drop(&mut self) {
unsafe {
pnsDestroyNet(self);
}
}
}
impl Default for Net {
fn default() -> Self {
Self::new()
}
}