use std::collections::HashMap;
use std::io::{BufRead, BufReader, Read, Write};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::process::{Child, ChildStdin, ChildStdout, Command, Stdio};
use std::ptr::NonNull;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::{Arc, Barrier};
use parking_lot::{Mutex, MutexGuard, RwLock};
use crate::{ActionTarget, LiveMod, Parameter};
pub struct LiveModHandle {
sender: Sender<Message>,
variables: Arc<RwLock<HashMap<String, ModVarHandle>>>,
barrier: Arc<Barrier>,
}
impl LiveModHandle {
pub fn new_gui() -> LiveModHandle {
Self::new_with_ui("livemod-gui")
}
pub fn new_with_ui(command: &str) -> LiveModHandle {
let mut child = Command::new(command)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
let (sender, recv) = mpsc::channel();
let output_sender = sender.clone();
let stdin = child.stdin.take().unwrap();
let stdout = child.stdout.take().unwrap();
let child_arc1 = Arc::new(child);
let child_arc2 = child_arc1.clone();
let variables_arc1 = Arc::new(RwLock::new(HashMap::new()));
let variables_arc2 = variables_arc1.clone();
let variables_arc3 = variables_arc1.clone();
let barrier_arc1 = Arc::new(Barrier::new(2));
let barrier_arc2 = barrier_arc1.clone();
std::thread::Builder::new()
.name("livemod_input".to_owned())
.spawn(|| {
input_thread(stdin, recv, variables_arc2);
drop(child_arc1);
})
.unwrap();
std::thread::Builder::new()
.name("livemod_output".to_owned())
.spawn(|| {
output_thread(stdout, output_sender, variables_arc3, barrier_arc2);
drop(child_arc2);
})
.unwrap();
LiveModHandle {
sender,
variables: variables_arc1,
barrier: barrier_arc1,
}
}
pub fn track_variable<T: LiveMod + 'static>(&self, name: &str, var: &'static StaticModVar<T>) {
let var_handle = ModVarHandle {
var: NonNull::from(&var.value),
};
self.sender
.send(Message::NewVariable(name.to_owned(), var_handle))
.unwrap();
}
pub fn create_variable<T: LiveMod + 'static>(&self, name: &str, var: T) -> ModVar<T> {
let mod_var = ModVar {
name: name.to_owned(),
value: Box::new(Mutex::new(var)),
sender: self.sender.clone(),
variables: self.variables.clone(),
};
let var_handle = ModVarHandle {
var: NonNull::from(&*mod_var.value),
};
self.sender
.send(Message::NewVariable(name.to_owned(), var_handle))
.unwrap();
mod_var
}
pub unsafe fn create_variable_unchecked<'a, T: LiveMod + 'a>(
&self,
name: &str,
var: T,
) -> ModVar<T> {
let mod_var = ModVar {
name: name.to_owned(),
value: Box::new(Mutex::new(var)),
sender: self.sender.clone(),
variables: self.variables.clone(),
};
let var_handle = ModVarHandle {
var: std::mem::transmute::<
NonNull<Mutex<dyn LiveMod + 'a>>,
NonNull<Mutex<dyn LiveMod + 'static>>,
>(NonNull::from(&*mod_var.value)),
};
self.sender
.send(Message::NewVariable(name.to_owned(), var_handle))
.unwrap();
mod_var
}
}
impl Drop for LiveModHandle {
fn drop(&mut self) {
self.sender.send(Message::Quit).unwrap();
self.barrier.wait();
}
}
pub struct ModVar<T> {
name: String,
value: Box<Mutex<T>>,
sender: Sender<Message>,
variables: Arc<RwLock<HashMap<String, ModVarHandle>>>,
}
impl<T: LiveMod> ModVar<T> {
pub fn lock(&self) -> ModVarGuard<T> {
ModVarGuard(self.value.lock())
}
pub fn lock_mut(&mut self) -> ModVarMutGuard<T> {
ModVarMutGuard(self.value.lock(), Some(UpdateMessage::new(self)))
}
}
impl<T> Drop for ModVar<T> {
fn drop(&mut self) {
self.sender
.send(Message::RemoveVariable(self.name.clone()))
.unwrap();
self.variables.write().remove(&self.name);
}
}
pub struct StaticModVar<T> {
value: Mutex<T>,
}
impl<T> StaticModVar<T> {
pub const fn new(value: T) -> StaticModVar<T> {
StaticModVar {
value: parking_lot::const_mutex(value),
}
}
pub fn lock(&self) -> ModVarGuard<T> {
ModVarGuard(self.value.lock())
}
}
pub struct ModVarGuard<'a, T>(MutexGuard<'a, T>);
impl<'a, T> Deref for ModVarGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
pub struct ModVarMutGuard<'a, T>(MutexGuard<'a, T>, Option<UpdateMessage<'a>>);
impl<'a, T> Deref for ModVarMutGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl<'a, T> DerefMut for ModVarMutGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
if let Some(msg) = self.1.take() {
msg.send();
}
&mut *self.0
}
}
struct UpdateMessage<'a> {
name: String,
handle: ModVarHandle,
sender: Sender<Message>,
_marker: PhantomData<&'a ModVarHandle>,
}
impl UpdateMessage<'_> {
fn new<'a, T: LiveMod + 'a>(var: &'a ModVar<T>) -> UpdateMessage<'a> {
UpdateMessage {
name: var.name.clone(),
handle: ModVarHandle {
var: unsafe {
std::mem::transmute::<
NonNull<Mutex<dyn LiveMod + 'a>>,
NonNull<Mutex<dyn LiveMod + 'static>>,
>(NonNull::from(&*var.value))
},
},
sender: var.sender.clone(),
_marker: std::marker::PhantomData,
}
}
fn send(self) {
self.sender
.send(Message::UpdatedVariable(self.name, self.handle))
.unwrap();
}
}
#[derive(Clone, Copy)]
struct ModVarHandle {
var: NonNull<Mutex<dyn LiveMod>>,
}
unsafe impl Send for ModVarHandle {}
unsafe impl Sync for ModVarHandle {}
enum Message {
NewVariable(String, ModVarHandle),
UpdatedVariable(String, ModVarHandle),
RemoveVariable(String),
UpdatedRepr(String),
Quit,
}
struct ChildDropper {
child: Child,
}
impl Drop for ChildDropper {
fn drop(&mut self) {
self.child.wait().unwrap();
}
}
fn input_thread(
mut input: ChildStdin,
recv: Receiver<Message>,
variables: Arc<RwLock<HashMap<String, ModVarHandle>>>,
) {
while let Ok(message) = recv.recv() {
match message {
Message::NewVariable(name, handle) => {
let var = unsafe { handle.var.as_ref() }.lock();
let repr = var.repr_default(ActionTarget::This).serialize();
let value = var.get_self(ActionTarget::This).serialize();
writeln!(
input,
"n{};{}-{};{}-{}",
&name,
repr.as_bytes().len(),
repr,
value.as_bytes().len(),
value,
)
.unwrap();
variables.write().insert(name, handle);
}
Message::UpdatedVariable(name, handle) => {
let var = unsafe { handle.var.as_ref() }.lock();
let value = var.get_self(ActionTarget::This).serialize();
writeln!(input, "s{};{}-{}", &name, value.as_bytes().len(), value,).unwrap();
}
Message::UpdatedRepr(name) => {
let var_handle =
unsafe { &mut *variables.read().get(&name).unwrap().var.as_ref().lock() };
let repr = var_handle.repr_default(ActionTarget::This).serialize();
let value = var_handle.get_self(ActionTarget::This).serialize();
writeln!(
input,
"u{};{}-{};{}-{}",
name,
repr.as_bytes().len(),
repr,
value.as_bytes().len(),
value,
)
.unwrap();
}
Message::RemoveVariable(name) => {
writeln!(input, "r{}", &name).unwrap();
}
Message::Quit => {
break;
}
}
}
}
fn output_thread(
output: ChildStdout,
sender: Sender<Message>,
variables: Arc<RwLock<HashMap<String, ModVarHandle>>>,
barrier: Arc<Barrier>,
) {
let mut reader = BufReader::new(output);
loop {
let message_type = {
let mut message_type = [0u8];
match reader.read_exact(&mut message_type) {
Ok(()) => message_type[0],
Err(_) => break,
}
};
match message_type {
b's' => {
let name = {
let mut name = Vec::new();
reader.read_until(b';', &mut name).unwrap();
name.pop(); String::from_utf8(name).unwrap()
};
let namespaced_name = name.split('.').collect::<Vec<_>>();
let value = {
let len = {
let mut len = Vec::new();
reader.read_until(b'-', &mut len).unwrap();
len.pop(); String::from_utf8(len).unwrap().parse::<usize>().unwrap()
};
let mut value = vec![0u8; len];
reader.read_exact(&mut value).unwrap();
Parameter::deserialize(&mut value.into_iter()).unwrap()
};
let base = namespaced_name.first().unwrap();
let referenced_var = unsafe {
&mut *match variables.read().get(*base) {
Some(base_handle) => base_handle,
None => {
continue;
}
}
.var
.as_ref()
.lock()
};
if referenced_var
.accept(ActionTarget::from_name_and_fields(&namespaced_name), value)
{
sender
.send(Message::UpdatedRepr(namespaced_name[0].to_owned()))
.unwrap();
}
}
_ => {}
}
}
barrier.wait();
}