mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
libraries can now work threaded if they wish (see http_requests). This means that multiple functions provided by one library can run at the same time (using thread(), see http.mers) and actually do the work they need to do simultaneously.
This commit is contained in:
parent
9b92c5b353
commit
a7bb3e67fa
17
http.mers
Normal file
17
http.mers
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
lib mers_libs/http_requests
|
||||||
|
|
||||||
|
t = thread(() {
|
||||||
|
// because this downloads for so long, the println() will appear after the other one.
|
||||||
|
http_get("https:\//raw.githubusercontent.com/dwyl/english-words/master/words.txt").assume_no_enum()
|
||||||
|
println("got words from word list!")
|
||||||
|
})
|
||||||
|
|
||||||
|
sleep(0.5)
|
||||||
|
|
||||||
|
// this will finish before the thread does.
|
||||||
|
http_get("https:\//github.com/").assume_no_enum()
|
||||||
|
println("got github start page as html")
|
||||||
|
|
||||||
|
// t.await()
|
||||||
|
|
||||||
|
http_get("not a url").debug()
|
@ -5,6 +5,16 @@ mod libs;
|
|||||||
mod parsing;
|
mod parsing;
|
||||||
mod script;
|
mod script;
|
||||||
|
|
||||||
pub use libs::inlib::*;
|
pub use libs::{
|
||||||
|
comms::{ByteData, ByteDataA, Message, RespondableMessage},
|
||||||
|
inlib::MyLib,
|
||||||
|
};
|
||||||
pub use parsing::*;
|
pub use parsing::*;
|
||||||
pub use script::{val_data::*, val_type::*};
|
pub use script::{val_data::*, val_type::*};
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use super::{
|
||||||
|
script::{val_data::*, val_type::*},
|
||||||
|
MyLib, RespondableMessage,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
542
mers/src/libs/comms.rs
Normal file
542
mers/src/libs/comms.rs
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
use crate::script::{
|
||||||
|
val_data::{VData, VDataEnum},
|
||||||
|
val_type::{VSingleType, VType},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// any message implements this trait. reponding to the message with A generates the response of type B.
|
||||||
|
pub trait RespondableMessage: MessageResponse {
|
||||||
|
type With;
|
||||||
|
type Response: MessageResponse;
|
||||||
|
fn respond(self, with: Self::With) -> Self::Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// any message or response implements this trait
|
||||||
|
pub trait MessageResponse: ByteData + ByteDataA {
|
||||||
|
fn messagetype_id() -> u32;
|
||||||
|
fn msgtype_id(&self) -> u32 {
|
||||||
|
Self::messagetype_id()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ByteData: Sized {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read;
|
||||||
|
}
|
||||||
|
/// for things like &str, which can't be created easily (String exists for that purpose), but can still be converted to bytes.
|
||||||
|
pub trait ByteDataA {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>);
|
||||||
|
fn as_byte_data_vec(&self) -> Vec<u8> {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
self.as_byte_data(&mut vec);
|
||||||
|
vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Message {
|
||||||
|
RunFunction(run_function::Message),
|
||||||
|
}
|
||||||
|
impl ByteData for Message {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut type_id = u32::from_byte_data(data)?;
|
||||||
|
Ok(match type_id {
|
||||||
|
0 => Self::RunFunction(ByteData::from_byte_data(data)?),
|
||||||
|
other => unreachable!("read unknown type_id byte for message!"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<run_function::Message> for Message {
|
||||||
|
fn from(value: run_function::Message) -> Self {
|
||||||
|
Self::RunFunction(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations for the message/response pairs
|
||||||
|
|
||||||
|
pub mod run_function {
|
||||||
|
use crate::script::val_data::VData;
|
||||||
|
|
||||||
|
use super::{ByteData, ByteDataA, MessageResponse, RespondableMessage};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Message {
|
||||||
|
pub function_id: u64,
|
||||||
|
pub args: Vec<VData>,
|
||||||
|
}
|
||||||
|
pub struct Response {
|
||||||
|
pub result: VData,
|
||||||
|
}
|
||||||
|
impl RespondableMessage for Message {
|
||||||
|
type With = VData;
|
||||||
|
type Response = Response;
|
||||||
|
fn respond(self, with: Self::With) -> Self::Response {
|
||||||
|
Response { result: with }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MessageResponse for Message {
|
||||||
|
fn messagetype_id() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MessageResponse for Response {
|
||||||
|
fn messagetype_id() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for Message {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.function_id.as_byte_data(vec);
|
||||||
|
self.args.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for Message {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
function_id: ByteData::from_byte_data(data)?,
|
||||||
|
args: ByteData::from_byte_data(data)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for Response {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.result.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for Response {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
result: ByteData::from_byte_data(data)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementations of ByteData for other data
|
||||||
|
|
||||||
|
type UsizeConstLen = u32;
|
||||||
|
type IsizeConstLen = i32;
|
||||||
|
|
||||||
|
impl ByteDataA for usize {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
(*self as UsizeConstLen).as_byte_data(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for usize {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(UsizeConstLen::from_byte_data(data)? as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for isize {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
(*self as IsizeConstLen).as_byte_data(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for isize {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(IsizeConstLen::from_byte_data(data)? as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for i32 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for i32 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 4];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for u32 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for u32 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 4];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for i64 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for i64 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 8];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for u64 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for u64 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 8];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for u128 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for u128 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 16];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for i128 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for i128 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 16];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for f64 {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
vec.extend_from_slice(&self.to_be_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for f64 {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut b = [0u8; 8];
|
||||||
|
data.read_exact(&mut b)?;
|
||||||
|
Ok(Self::from_be_bytes(b))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for String {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.len().as_byte_data(vec);
|
||||||
|
vec.extend_from_slice(self.as_bytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for String {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let len = ByteData::from_byte_data(data)?;
|
||||||
|
let mut buf = vec![0; len];
|
||||||
|
data.read_exact(buf.as_mut_slice());
|
||||||
|
let str = String::from_utf8(buf).unwrap();
|
||||||
|
Ok(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ByteDataA for &T
|
||||||
|
where
|
||||||
|
T: ByteDataA,
|
||||||
|
{
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
(*self).as_byte_data(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ByteDataA for Vec<T>
|
||||||
|
where
|
||||||
|
T: ByteDataA,
|
||||||
|
{
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.len().as_byte_data(vec);
|
||||||
|
for elem in self {
|
||||||
|
elem.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> ByteData for Vec<T>
|
||||||
|
where
|
||||||
|
T: ByteData,
|
||||||
|
{
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let len = usize::from_byte_data(data)?;
|
||||||
|
let mut vec = Vec::with_capacity(len);
|
||||||
|
for _ in 0..len {
|
||||||
|
vec.push(T::from_byte_data(data)?);
|
||||||
|
}
|
||||||
|
Ok(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B> ByteDataA for (A, B)
|
||||||
|
where
|
||||||
|
A: ByteDataA,
|
||||||
|
B: ByteDataA,
|
||||||
|
{
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.0.as_byte_data(vec);
|
||||||
|
self.1.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B> ByteData for (A, B)
|
||||||
|
where
|
||||||
|
A: ByteData,
|
||||||
|
B: ByteData,
|
||||||
|
{
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok((
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B, C, D, E> ByteDataA for (A, B, C, D, E)
|
||||||
|
where
|
||||||
|
A: ByteDataA,
|
||||||
|
B: ByteDataA,
|
||||||
|
C: ByteDataA,
|
||||||
|
D: ByteDataA,
|
||||||
|
E: ByteDataA,
|
||||||
|
{
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.0.as_byte_data(vec);
|
||||||
|
self.1.as_byte_data(vec);
|
||||||
|
self.2.as_byte_data(vec);
|
||||||
|
self.3.as_byte_data(vec);
|
||||||
|
self.4.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<A, B, C, D, E> ByteData for (A, B, C, D, E)
|
||||||
|
where
|
||||||
|
A: ByteData,
|
||||||
|
B: ByteData,
|
||||||
|
C: ByteData,
|
||||||
|
D: ByteData,
|
||||||
|
E: ByteData,
|
||||||
|
{
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok((
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for VType {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.types.as_byte_data(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for VType {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
types: ByteData::from_byte_data(data)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for VSingleType {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
match self {
|
||||||
|
Self::Bool => vec.push(b'b'),
|
||||||
|
Self::Int => vec.push(b'i'),
|
||||||
|
Self::Float => vec.push(b'f'),
|
||||||
|
Self::String => vec.push(b'"'),
|
||||||
|
Self::Tuple(v) => {
|
||||||
|
vec.push(b't');
|
||||||
|
v.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::List(v) => {
|
||||||
|
vec.push(b'l');
|
||||||
|
v.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::Function(f) => {
|
||||||
|
vec.push(b'F');
|
||||||
|
f.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::Thread(r) => {
|
||||||
|
vec.push(b'T');
|
||||||
|
r.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::Reference(r) => {
|
||||||
|
vec.push(b'R');
|
||||||
|
r.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::EnumVariant(e, v) => {
|
||||||
|
vec.push(b'e');
|
||||||
|
e.as_byte_data(vec);
|
||||||
|
v.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::EnumVariantS(e, v) => {
|
||||||
|
vec.push(b'E');
|
||||||
|
e.as_byte_data(vec);
|
||||||
|
v.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::CustomType(_) | Self::CustomTypeS(_) => {
|
||||||
|
unreachable!("CustomType and CustomTypeS cannot be used in libraries [yet?].")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for VSingleType {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut switch_byte = [0u8];
|
||||||
|
data.read_exact(&mut switch_byte)?;
|
||||||
|
Ok(match switch_byte[0] {
|
||||||
|
b'b' => Self::Bool,
|
||||||
|
b'i' => Self::Int,
|
||||||
|
b'f' => Self::Float,
|
||||||
|
b'"' => Self::String,
|
||||||
|
b't' => Self::Tuple(ByteData::from_byte_data(data)?),
|
||||||
|
b'l' => Self::List(ByteData::from_byte_data(data)?),
|
||||||
|
b'F' => Self::Function(ByteData::from_byte_data(data)?),
|
||||||
|
b'T' => Self::Thread(ByteData::from_byte_data(data)?),
|
||||||
|
b'R' => Self::Reference(Box::new(ByteData::from_byte_data(data)?)),
|
||||||
|
b'e' => Self::EnumVariant(
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
),
|
||||||
|
b'E' => Self::EnumVariantS(
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
),
|
||||||
|
_ => unreachable!("unexpected byte while reading single type"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for VData {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
self.data.as_byte_data(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for VData {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
Ok(Self {
|
||||||
|
data: ByteData::from_byte_data(data)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteDataA for VDataEnum {
|
||||||
|
fn as_byte_data(&self, vec: &mut Vec<u8>) {
|
||||||
|
match self {
|
||||||
|
Self::Bool(false) => vec.push(b'b'),
|
||||||
|
Self::Bool(true) => vec.push(b'B'),
|
||||||
|
Self::Int(num) => {
|
||||||
|
vec.push(b'i');
|
||||||
|
num.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::Float(num) => {
|
||||||
|
vec.push(b'f');
|
||||||
|
num.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::String(s) => {
|
||||||
|
vec.push(b'"');
|
||||||
|
s.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::Tuple(c) => {
|
||||||
|
vec.push(b't');
|
||||||
|
c.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
Self::List(_, data) => {
|
||||||
|
vec.push(b'l');
|
||||||
|
data.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
// TODO?
|
||||||
|
Self::Function(_) => vec.push(b'F'),
|
||||||
|
Self::Thread(..) => vec.push(b'T'),
|
||||||
|
Self::Reference(r) => vec.push(b'R'),
|
||||||
|
Self::EnumVariant(enum_id, inner) => {
|
||||||
|
vec.push(b'E');
|
||||||
|
enum_id.as_byte_data(vec);
|
||||||
|
inner.as_byte_data(vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ByteData for VDataEnum {
|
||||||
|
fn from_byte_data<R>(data: &mut R) -> Result<Self, std::io::Error>
|
||||||
|
where
|
||||||
|
R: std::io::Read,
|
||||||
|
{
|
||||||
|
let mut switch_byte = [0u8];
|
||||||
|
data.read_exact(&mut switch_byte)?;
|
||||||
|
Ok(match switch_byte[0] {
|
||||||
|
b'b' => Self::Bool(false),
|
||||||
|
b'B' => Self::Bool(true),
|
||||||
|
b'i' => Self::Int(ByteData::from_byte_data(data)?),
|
||||||
|
b'f' => Self::Float(ByteData::from_byte_data(data)?),
|
||||||
|
b'"' => Self::String(ByteData::from_byte_data(data)?),
|
||||||
|
b't' => Self::Tuple(ByteData::from_byte_data(data)?),
|
||||||
|
b'l' => {
|
||||||
|
let entries: Vec<VData> = ByteData::from_byte_data(data)?;
|
||||||
|
Self::List(
|
||||||
|
entries.iter().fold(VType::empty(), |t, v| t | v.out()),
|
||||||
|
entries,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
b'E' => Self::EnumVariant(
|
||||||
|
ByteData::from_byte_data(data)?,
|
||||||
|
Box::new(ByteData::from_byte_data(data)?),
|
||||||
|
),
|
||||||
|
_ => unreachable!("read invalid byte"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,145 +1,147 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io::{BufRead, Write},
|
io::{BufRead, Stdin, StdinLock, Stdout, StdoutLock, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::script::{val_data::VData, val_type::VType};
|
||||||
libs::DirectReader,
|
|
||||||
script::{val_data::VData, val_type::VType},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{data_from_bytes, data_to_bytes};
|
use super::{
|
||||||
|
comms::{self, ByteData, ByteDataA, Message, MessageResponse, RespondableMessage},
|
||||||
|
LibInitInfo, LibInitReq,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct MyLib {
|
pub struct MyLib {
|
||||||
name: String,
|
// name: String,
|
||||||
version: (u8, u8),
|
version: (u32, u32),
|
||||||
description: String,
|
// description: String,
|
||||||
functions: Vec<(String, Vec<VType>, VType)>,
|
// functions: Vec<(String, Vec<VType>, VType)>,
|
||||||
enum_variants: HashMap<String, usize>,
|
pub callbacks: Callbacks,
|
||||||
|
enum_variants: Vec<(String, usize)>,
|
||||||
|
stdin: StdinLock<'static>,
|
||||||
|
stdin_no_lock: Stdin,
|
||||||
}
|
}
|
||||||
impl MyLib {
|
impl MyLib {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: String,
|
name: String,
|
||||||
version: (u8, u8),
|
version: (u32, u32),
|
||||||
description: String,
|
description: String,
|
||||||
functions: Vec<(String, Vec<VType>, VType)>,
|
functions: Vec<(String, Vec<(Vec<VType>, VType)>)>,
|
||||||
) -> (Self, MyLibTaskCompletion) {
|
) -> Self {
|
||||||
(
|
let stdout_no_lock = std::io::stdout();
|
||||||
Self {
|
let stdin_no_lock = std::io::stdin();
|
||||||
name,
|
let mut stdout = stdout_no_lock.lock();
|
||||||
version,
|
let mut stdin = stdin_no_lock.lock();
|
||||||
description,
|
// comms version
|
||||||
functions,
|
stdout.write(1u128.as_byte_data_vec().as_slice()).unwrap();
|
||||||
enum_variants: HashMap::new(),
|
let init_req: LibInitReq = (version.0, version.1, name, description, functions);
|
||||||
},
|
stdout
|
||||||
MyLibTaskCompletion { _priv: () },
|
.write(init_req.as_byte_data_vec().as_slice())
|
||||||
)
|
.unwrap();
|
||||||
|
stdout.flush();
|
||||||
|
let enum_variants = LibInitInfo::from_byte_data(&mut stdin).unwrap();
|
||||||
|
Self {
|
||||||
|
// name: name.clone(),
|
||||||
|
version,
|
||||||
|
// description: description.clone(),
|
||||||
|
// functions: functions.clone(),
|
||||||
|
callbacks: Callbacks::empty(),
|
||||||
|
enum_variants,
|
||||||
|
stdin,
|
||||||
|
stdin_no_lock,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn get_enum(&self, e: &str) -> Option<usize> {
|
pub fn get_enums(&self) -> &Vec<(String, usize)> {
|
||||||
self.enum_variants.get(e).map(|v| *v)
|
&self.enum_variants
|
||||||
}
|
}
|
||||||
pub fn run<I, O>(
|
fn get_one_msg(&mut self) -> Result<Result<(), Message>, std::io::Error> {
|
||||||
&mut self,
|
let id = u128::from_byte_data(&mut self.stdin)?;
|
||||||
run: MyLibTaskCompletion,
|
let message = Message::from_byte_data(&mut self.stdin)?;
|
||||||
stdin: &mut I,
|
match message {
|
||||||
stdout: &mut O,
|
Message::RunFunction(msg) => self.callbacks.run_function.run(Respondable::new(id, msg)),
|
||||||
) -> MyLibTask
|
};
|
||||||
where
|
Ok(Ok(()))
|
||||||
I: BufRead,
|
}
|
||||||
O: Write,
|
pub fn get_next_unhandled_message(&mut self) -> Result<(), Message> {
|
||||||
{
|
loop {
|
||||||
drop(run);
|
match self.get_one_msg() {
|
||||||
match match stdin.one_byte().unwrap().into() {
|
Ok(Ok(())) => {}
|
||||||
'i' => {
|
// unhandled message. return it to be handeled or included in the error
|
||||||
assert_eq!(stdin.one_byte().unwrap() as char, '\n');
|
Ok(Err(msg)) => return Err(msg),
|
||||||
stdout.write(&[self.version.0, self.version.1]).unwrap();
|
// i/o error, probably because mers exited. return successfully.
|
||||||
writeln!(stdout, "{}", self.name).unwrap();
|
Err(e) => return Ok(()),
|
||||||
stdout
|
|
||||||
.write(&[self.description.split('\n').count() as _])
|
|
||||||
.unwrap();
|
|
||||||
writeln!(stdout, "{}", self.description).unwrap();
|
|
||||||
for func in self.functions.iter() {
|
|
||||||
writeln!(
|
|
||||||
stdout,
|
|
||||||
"f{}({}) {}",
|
|
||||||
func.0,
|
|
||||||
func.1
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, v)| if i == 0 {
|
|
||||||
format!("{v}")
|
|
||||||
} else {
|
|
||||||
format!(" {v}")
|
|
||||||
})
|
|
||||||
.collect::<String>(),
|
|
||||||
func.2
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
writeln!(stdout, "x").unwrap();
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
'I' => {
|
|
||||||
let mut line = String::new();
|
|
||||||
loop {
|
|
||||||
line.clear();
|
|
||||||
stdin.read_line(&mut line).unwrap();
|
|
||||||
if let Some((task, args)) = line.split_once(' ') {
|
|
||||||
match task {
|
|
||||||
"set_enum_id" => {
|
|
||||||
let (enum_name, enum_id) = args.split_once(' ').unwrap();
|
|
||||||
let name = enum_name.trim().to_string();
|
|
||||||
let id = enum_id.trim().parse().unwrap();
|
|
||||||
self.enum_variants.insert(name.clone(), id);
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match line.trim_end() {
|
|
||||||
"init_finished" => break,
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(MyLibTask::FinishedInit(MyLibTaskCompletion { _priv: () }))
|
|
||||||
}
|
|
||||||
'f' => {
|
|
||||||
let fnid = stdin.one_byte().unwrap() as usize;
|
|
||||||
Some(MyLibTask::RunFunction(MyLibTaskRunFunction {
|
|
||||||
function: fnid,
|
|
||||||
args: self.functions[fnid]
|
|
||||||
.1
|
|
||||||
.iter()
|
|
||||||
.map(|_| data_from_bytes(stdin).to())
|
|
||||||
.collect(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
} {
|
|
||||||
Some(v) => v,
|
|
||||||
None => MyLibTask::None(MyLibTaskCompletion { _priv: () }),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum MyLibTask {
|
pub struct Respondable<M> {
|
||||||
None(MyLibTaskCompletion),
|
id: u128,
|
||||||
FinishedInit(MyLibTaskCompletion),
|
pub msg: M,
|
||||||
RunFunction(MyLibTaskRunFunction),
|
|
||||||
}
|
}
|
||||||
pub struct MyLibTaskRunFunction {
|
impl<M> Respondable<M> {
|
||||||
pub function: usize,
|
fn new(id: u128, msg: M) -> Self {
|
||||||
pub args: Vec<VData>,
|
Self { id, msg }
|
||||||
}
|
|
||||||
impl MyLibTaskRunFunction {
|
|
||||||
pub fn done<O>(self, o: &mut O, returns: VData) -> MyLibTaskCompletion
|
|
||||||
where
|
|
||||||
O: Write,
|
|
||||||
{
|
|
||||||
data_to_bytes(&returns, o);
|
|
||||||
MyLibTaskCompletion { _priv: () }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub struct MyLibTaskCompletion {
|
impl<M> Respondable<M>
|
||||||
_priv: (),
|
where
|
||||||
|
M: RespondableMessage,
|
||||||
|
{
|
||||||
|
pub fn respond(self, with: M::With) {
|
||||||
|
let mut stdout = std::io::stdout().lock();
|
||||||
|
stdout.write(&self.id.as_byte_data_vec()).unwrap();
|
||||||
|
stdout
|
||||||
|
.write(&self.msg.respond(with).as_byte_data_vec())
|
||||||
|
.unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<M> Respondable<M>
|
||||||
|
where
|
||||||
|
M: Into<Message>,
|
||||||
|
{
|
||||||
|
pub fn to_general(self) -> Respondable<Message> {
|
||||||
|
Respondable::new(self.id, self.msg.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Callbacks {
|
||||||
|
pub run_function: Callback<comms::run_function::Message>,
|
||||||
|
}
|
||||||
|
impl Callbacks {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
run_function: Callback::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct Callback<M>
|
||||||
|
where
|
||||||
|
M: super::comms::RespondableMessage,
|
||||||
|
{
|
||||||
|
pub nonconsuming: Vec<Box<dyn FnMut(&M)>>,
|
||||||
|
pub consuming: Option<Box<dyn FnMut(Respondable<M>)>>,
|
||||||
|
}
|
||||||
|
impl<M> Callback<M>
|
||||||
|
where
|
||||||
|
M: super::comms::RespondableMessage,
|
||||||
|
{
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
nonconsuming: vec![],
|
||||||
|
consuming: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// If the event was handled by a consuming function, returns Ok(r) where r is the returned value from the consuming function.
|
||||||
|
/// If it wasn't handled (or only handled by nonconsuming functions), Err(m) is returned, giving ownership of the original message back to the caller for further handling.
|
||||||
|
pub fn run(&mut self, msg: Respondable<M>) -> Result<(), Respondable<M>> {
|
||||||
|
for f in self.nonconsuming.iter_mut() {
|
||||||
|
f(&msg.msg);
|
||||||
|
}
|
||||||
|
if let Some(f) = self.consuming.as_mut() {
|
||||||
|
Ok(f(msg))
|
||||||
|
} else {
|
||||||
|
Err(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod comms;
|
||||||
pub mod inlib;
|
pub mod inlib;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
|
|
||||||
@ -10,56 +11,30 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
libs::comms::{ByteData, ByteDataA},
|
||||||
parsing::{file::File, parse},
|
parsing::{file::File, parse},
|
||||||
script::{
|
script::{
|
||||||
|
global_info::GlobalScriptInfo,
|
||||||
val_data::{VData, VDataEnum},
|
val_data::{VData, VDataEnum},
|
||||||
val_type::VType,
|
val_type::VType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
use self::comms::{MessageResponse, RespondableMessage};
|
||||||
Libraries are processes that communicate via stdout/stdin.
|
|
||||||
data in stdout is only expected after it was requested via stdin. ignoring this will likely cause issues.
|
|
||||||
requests in stdin can be identified via the first byte (ascii char) and end with a \n newline character.
|
|
||||||
the identifying ascii chars:
|
|
||||||
i init
|
|
||||||
reply format:
|
|
||||||
two bytes, the first for major and the second for minor version number.
|
|
||||||
the utf8-encoded name of the library followed by a newline
|
|
||||||
the number of lines in the description (0 for no description) as a byte. (more than 255 lines aren't supported)
|
|
||||||
a (optionally markdown-formatted [TODO!]) description of the library; all lines (including the last one) must end with a newline
|
|
||||||
the things you would like to register; one line each unless explicitly stated otherwise; the first byte (char) decides what type to register:
|
|
||||||
f a function: followed by the function signature, i.e. "my_func(string int/float [string]) string/[float int]"
|
|
||||||
x end: indicates that you are done registering things
|
|
||||||
I init 2
|
|
||||||
can send some tasks,
|
|
||||||
must end with a line saying 'init_finished'.
|
|
||||||
reply should be a single line (only the newline char). If there is data before the newline char, it will be reported as an error and the script will not run.
|
|
||||||
f call a function:
|
|
||||||
followed by the function id byte (0 <= id < #funcs; function ids are assigned in ascending order as they were registered in the reply to "i"
|
|
||||||
and the data for each argument, in order.
|
|
||||||
reply: the data for the returned value
|
|
||||||
x exit
|
|
||||||
sending data: (all ints are encoded so that the most significant data is sent FIRST)
|
|
||||||
the first byte (ascii char) identifies the type of data: (exceptions listed first: bools)
|
|
||||||
b false
|
|
||||||
B true
|
|
||||||
1 int
|
|
||||||
2 int as string
|
|
||||||
5 float
|
|
||||||
6 float as string
|
|
||||||
" string (format: ", 64-bit unsigned int indicating string length, so many bytes utf-8)
|
|
||||||
|
|
||||||
|
// Libraries are processes that communicate via stdout/stdin.
|
||||||
*/
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Lib {
|
pub struct Lib {
|
||||||
name: String,
|
name: String,
|
||||||
process: Child,
|
process: Child,
|
||||||
|
current_id: Arc<Mutex<u128>>,
|
||||||
stdin: Arc<Mutex<ChildStdin>>,
|
stdin: Arc<Mutex<ChildStdin>>,
|
||||||
stdout: Arc<Mutex<BufReader<ChildStdout>>>,
|
// stdout: Arc<Mutex<BufReader<ChildStdout>>>,
|
||||||
pub registered_fns: Vec<(String, Vec<VType>, VType)>,
|
task_sender: Arc<
|
||||||
|
Mutex<std::sync::mpsc::Sender<(u128, Box<dyn FnOnce(&mut BufReader<ChildStdout>) + Send>)>>,
|
||||||
|
>,
|
||||||
|
pub registered_fns: Vec<(String, Vec<(Vec<VType>, VType)>)>,
|
||||||
}
|
}
|
||||||
impl Drop for Lib {
|
impl Drop for Lib {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
@ -73,6 +48,20 @@ impl Drop for Lib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Sent by the library to request initialization
|
||||||
|
/// ([ver_major], [ver_minor], [name], [desc], [registered_functions])
|
||||||
|
pub type LibInitReq<'a> = (
|
||||||
|
u32,
|
||||||
|
u32,
|
||||||
|
String,
|
||||||
|
String,
|
||||||
|
Vec<(String, Vec<(Vec<VType>, VType)>)>,
|
||||||
|
);
|
||||||
|
/// Sent by mers to finish initializing a library.
|
||||||
|
/// [enum variants]
|
||||||
|
pub type LibInitInfo = Vec<(String, usize)>;
|
||||||
|
pub type LibInitInfoRef<'a> = Vec<(&'a String, &'a usize)>;
|
||||||
|
|
||||||
impl Lib {
|
impl Lib {
|
||||||
pub fn launch(
|
pub fn launch(
|
||||||
mut exec: Command,
|
mut exec: Command,
|
||||||
@ -89,75 +78,84 @@ impl Lib {
|
|||||||
};
|
};
|
||||||
if let (Some(mut stdin), Some(stdout)) = (handle.stdin.take(), handle.stdout.take()) {
|
if let (Some(mut stdin), Some(stdout)) = (handle.stdin.take(), handle.stdout.take()) {
|
||||||
let mut stdout = BufReader::new(stdout);
|
let mut stdout = BufReader::new(stdout);
|
||||||
writeln!(stdin, "i").unwrap();
|
let comms_version: u128 = ByteData::from_byte_data(&mut stdout).unwrap();
|
||||||
let vernum = {
|
assert_eq!(comms_version, 1);
|
||||||
let mut vernum = [0, 0];
|
let (ver_major, ver_minor, name, description, mut registered_fns) =
|
||||||
stdout.read_exact(&mut vernum).unwrap();
|
LibInitReq::from_byte_data(&mut stdout).unwrap();
|
||||||
(vernum[0], vernum[1])
|
eprintln!("- <<< ADDING LIB: {name} v{ver_major}.{ver_minor} >>> -");
|
||||||
};
|
for line in description.lines() {
|
||||||
let name = stdout.line().unwrap();
|
eprintln!(" | {line}");
|
||||||
let name = name.trim();
|
|
||||||
eprintln!("- <<< ADDING LIB: {name} v{}.{} >>> -", vernum.0, vernum.1);
|
|
||||||
let lines_in_desc = stdout.one_byte().unwrap();
|
|
||||||
let mut lines_desc = Vec::with_capacity(lines_in_desc as _);
|
|
||||||
for _ in 0..lines_in_desc {
|
|
||||||
let line = stdout.line().unwrap();
|
|
||||||
let line = line.trim_end_matches('\n');
|
|
||||||
eprintln!("| {line}");
|
|
||||||
lines_desc.push(line.to_string());
|
|
||||||
}
|
}
|
||||||
let mut registered_fns = vec![];
|
for (name, _) in registered_fns.iter() {
|
||||||
loop {
|
eprintln!(" fn {name}");
|
||||||
let line = stdout.line().unwrap();
|
}
|
||||||
match line.chars().next() {
|
let mut ginfo = GlobalScriptInfo::default();
|
||||||
Some('f') => {
|
for (_name, func) in registered_fns.iter_mut() {
|
||||||
let (name, args) = line[1..]
|
for (args, out) in func.iter_mut() {
|
||||||
.split_once('(')
|
for t in args.iter_mut() {
|
||||||
.expect("function signature didn't include the ( character.");
|
crate::script::to_runnable::stypes(t, &mut ginfo);
|
||||||
let mut fn_signature = File::new(args.to_string(), PathBuf::new());
|
|
||||||
let mut fn_in = vec![];
|
|
||||||
fn_signature.skip_whitespaces();
|
|
||||||
if let Some(')') = fn_signature.peek() {
|
|
||||||
fn_signature.next();
|
|
||||||
} else {
|
|
||||||
loop {
|
|
||||||
let mut t = match parse::implementation::parse_type_adv(
|
|
||||||
&mut fn_signature,
|
|
||||||
true,
|
|
||||||
) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => panic!("{e}"),
|
|
||||||
};
|
|
||||||
t.0.enum_variants(enum_variants);
|
|
||||||
fn_in.push(t.0);
|
|
||||||
if t.1 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut fn_out = match parse::implementation::parse_type(&mut fn_signature)
|
|
||||||
{
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => panic!("{e}"),
|
|
||||||
};
|
|
||||||
fn_out.enum_variants(enum_variants);
|
|
||||||
eprintln!("Registering function \"{name}\" with args \"{}\" and return type \"{fn_out}\"", &fn_in.iter().fold(String::new(), |mut s, v| { s.push_str(format!(" {}", v).as_str()); s }).trim_start_matches(' '));
|
|
||||||
registered_fns.push((name.to_string(), fn_in, fn_out));
|
|
||||||
}
|
}
|
||||||
Some('x') => break,
|
crate::script::to_runnable::stypes(out, &mut ginfo);
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write!(stdin, "I").unwrap();
|
for (name, id) in ginfo.enum_variants {
|
||||||
for (enum_name, enum_id) in enum_variants.iter() {
|
if !enum_variants.contains_key(&name) {
|
||||||
writeln!(stdin, "set_enum_id {enum_name} {enum_id}").unwrap();
|
enum_variants.insert(name, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writeln!(stdin, "init_finished").unwrap();
|
let si: LibInitInfoRef = enum_variants.iter().collect();
|
||||||
|
stdin.write(si.as_byte_data_vec().as_slice());
|
||||||
|
stdin.flush();
|
||||||
|
let (task_sender, recv) = std::sync::mpsc::channel::<(
|
||||||
|
u128,
|
||||||
|
Box<dyn FnOnce(&mut BufReader<ChildStdout>) + Send>,
|
||||||
|
)>();
|
||||||
|
let stdout_reader = std::thread::spawn(move || {
|
||||||
|
let dur = std::time::Duration::from_millis(20);
|
||||||
|
let mut pending = HashMap::new();
|
||||||
|
loop {
|
||||||
|
// read id from stdout
|
||||||
|
if let Ok(id) = u128::from_byte_data(&mut stdout) {
|
||||||
|
// update pending
|
||||||
|
loop {
|
||||||
|
if let Ok((id, sender)) = recv.try_recv() {
|
||||||
|
pending.insert(id, sender);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// find task with that id
|
||||||
|
if let Some(sender) = pending.remove(&id) {
|
||||||
|
// call the callback function, which will handle the rest
|
||||||
|
sender(&mut stdout)
|
||||||
|
} else {
|
||||||
|
eprintln!("ID {id} not found! possible decode/encode error?");
|
||||||
|
}
|
||||||
|
std::thread::sleep(dur);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Library has exited, tasks pending: {}",
|
||||||
|
pending.iter().enumerate().fold(
|
||||||
|
String::new(),
|
||||||
|
|mut s, (i, (id, _))| if i == 0 {
|
||||||
|
format!("{id}")
|
||||||
|
} else {
|
||||||
|
s.push_str(format!(", {id}").as_str());
|
||||||
|
s
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: name.to_string(),
|
name,
|
||||||
process: handle,
|
process: handle,
|
||||||
stdin: Arc::new(Mutex::new(stdin)),
|
stdin: Arc::new(Mutex::new(stdin)),
|
||||||
stdout: Arc::new(Mutex::new(stdout)),
|
// stdout: Arc::new(Mutex::new(stdout)),
|
||||||
|
task_sender: Arc::new(Mutex::new(task_sender)),
|
||||||
|
current_id: Arc::new(Mutex::new(0)),
|
||||||
registered_fns,
|
registered_fns,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -165,17 +163,45 @@ impl Lib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_fn(&self, fnid: usize, args: &Vec<VData>) -> VData {
|
pub fn run_fn(&self, fnid: usize, args: Vec<VData>) -> VData {
|
||||||
let mut stdin = self.stdin.lock().unwrap();
|
self.get_response(comms::run_function::Message {
|
||||||
let mut stdout = self.stdout.lock().unwrap();
|
function_id: fnid as _,
|
||||||
debug_assert!(args.len() == self.registered_fns[fnid].1.len());
|
args,
|
||||||
write!(stdin, "f").unwrap();
|
})
|
||||||
stdin.write(&[fnid as _]).unwrap();
|
.result
|
||||||
for (_i, arg) in args.iter().enumerate() {
|
}
|
||||||
data_to_bytes(arg, &mut *stdin);
|
fn get_response<M>(&self, msg: M) -> M::Response
|
||||||
}
|
where
|
||||||
let o = data_from_bytes(&mut *stdout).to();
|
M: RespondableMessage,
|
||||||
o
|
<M as comms::RespondableMessage>::Response: Send + 'static,
|
||||||
|
{
|
||||||
|
let recv = {
|
||||||
|
let mut id = self.current_id.lock().unwrap();
|
||||||
|
let mut stdin = self.stdin.lock().unwrap();
|
||||||
|
let (sender, recv) = std::sync::mpsc::sync_channel(2);
|
||||||
|
self.task_sender
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send((
|
||||||
|
*id,
|
||||||
|
Box::new(move |stdout| {
|
||||||
|
sender
|
||||||
|
.send(ByteData::from_byte_data(stdout).unwrap())
|
||||||
|
.unwrap();
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
// id - type_id - message
|
||||||
|
stdin.write(id.as_byte_data_vec().as_slice()).unwrap();
|
||||||
|
stdin
|
||||||
|
.write(msg.msgtype_id().as_byte_data_vec().as_slice())
|
||||||
|
.unwrap();
|
||||||
|
stdin.write(msg.as_byte_data_vec().as_slice()).unwrap();
|
||||||
|
stdin.flush().unwrap();
|
||||||
|
*id = id.wrapping_add(1);
|
||||||
|
recv
|
||||||
|
};
|
||||||
|
recv.recv().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,151 +218,3 @@ impl std::fmt::Display for LaunchError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DirectReader {
|
|
||||||
fn line(&mut self) -> Result<String, io::Error>;
|
|
||||||
fn one_byte(&mut self) -> Result<u8, io::Error>;
|
|
||||||
}
|
|
||||||
impl<T> DirectReader for T
|
|
||||||
where
|
|
||||||
T: BufRead,
|
|
||||||
{
|
|
||||||
fn line(&mut self) -> Result<String, io::Error> {
|
|
||||||
let mut buf = String::new();
|
|
||||||
self.read_line(&mut buf)?;
|
|
||||||
Ok(buf)
|
|
||||||
}
|
|
||||||
fn one_byte(&mut self) -> Result<u8, io::Error> {
|
|
||||||
let mut b = [0];
|
|
||||||
self.read(&mut b)?;
|
|
||||||
Ok(b[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data_to_bytes<T>(data: &VData, stdin: &mut T)
|
|
||||||
where
|
|
||||||
T: Write,
|
|
||||||
{
|
|
||||||
match &data.data {
|
|
||||||
VDataEnum::Bool(false) => write!(stdin, "b").unwrap(),
|
|
||||||
VDataEnum::Bool(true) => write!(stdin, "B").unwrap(),
|
|
||||||
VDataEnum::Int(v) => {
|
|
||||||
let mut v = *v;
|
|
||||||
let mut b = [0u8; 8];
|
|
||||||
for i in (0..8).rev() {
|
|
||||||
b[i] = (v & 0xFF) as _;
|
|
||||||
v >>= 8;
|
|
||||||
}
|
|
||||||
write!(stdin, "1").unwrap();
|
|
||||||
stdin.write(&b).unwrap();
|
|
||||||
}
|
|
||||||
VDataEnum::Float(f) => {
|
|
||||||
writeln!(stdin, "6{f}").unwrap();
|
|
||||||
}
|
|
||||||
VDataEnum::String(s) => {
|
|
||||||
write!(stdin, "\"").unwrap();
|
|
||||||
stdin.write(&(s.len() as u64).to_be_bytes()).unwrap();
|
|
||||||
stdin.write(s.as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
VDataEnum::Tuple(v) => {
|
|
||||||
write!(stdin, "t").unwrap();
|
|
||||||
for v in v {
|
|
||||||
write!(stdin, "+").unwrap();
|
|
||||||
data_to_bytes(v, stdin);
|
|
||||||
}
|
|
||||||
writeln!(stdin).unwrap();
|
|
||||||
}
|
|
||||||
VDataEnum::List(_, v) => {
|
|
||||||
write!(stdin, "l").unwrap();
|
|
||||||
for v in v {
|
|
||||||
write!(stdin, "+").unwrap();
|
|
||||||
data_to_bytes(v, stdin);
|
|
||||||
}
|
|
||||||
writeln!(stdin).unwrap();
|
|
||||||
}
|
|
||||||
VDataEnum::Function(..) | VDataEnum::Reference(..) | VDataEnum::Thread(..) => {
|
|
||||||
panic!("cannot use functions, references or threads in LibFunctions.")
|
|
||||||
}
|
|
||||||
VDataEnum::EnumVariant(e, v) => {
|
|
||||||
stdin
|
|
||||||
.write(
|
|
||||||
['E' as u8]
|
|
||||||
.into_iter()
|
|
||||||
.chain((*e as u64).to_be_bytes().into_iter())
|
|
||||||
.collect::<Vec<u8>>()
|
|
||||||
.as_slice(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
data_to_bytes(v.as_ref(), stdin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stdin.flush().unwrap();
|
|
||||||
}
|
|
||||||
pub fn data_from_bytes<T>(stdout: &mut T) -> VDataEnum
|
|
||||||
where
|
|
||||||
T: BufRead,
|
|
||||||
{
|
|
||||||
let id_byte = stdout.one_byte().unwrap().into();
|
|
||||||
match id_byte {
|
|
||||||
'b' => VDataEnum::Bool(false),
|
|
||||||
'B' => VDataEnum::Bool(true),
|
|
||||||
'1' => {
|
|
||||||
let mut num = 0;
|
|
||||||
for _ in 0..8 {
|
|
||||||
num <<= 8;
|
|
||||||
num |= stdout.one_byte().unwrap() as isize;
|
|
||||||
}
|
|
||||||
VDataEnum::Int(num)
|
|
||||||
}
|
|
||||||
'2' => {
|
|
||||||
let mut buf = String::new();
|
|
||||||
stdout.read_line(&mut buf).unwrap();
|
|
||||||
VDataEnum::Int(buf.parse().unwrap())
|
|
||||||
}
|
|
||||||
'5' => {
|
|
||||||
let mut num = 0;
|
|
||||||
for _ in 0..8 {
|
|
||||||
num <<= 8;
|
|
||||||
num |= stdout.one_byte().unwrap() as u64;
|
|
||||||
}
|
|
||||||
VDataEnum::Float(f64::from_bits(num))
|
|
||||||
}
|
|
||||||
'6' => {
|
|
||||||
let mut buf = String::new();
|
|
||||||
stdout.read_line(&mut buf).unwrap();
|
|
||||||
VDataEnum::Float(buf.parse().unwrap())
|
|
||||||
}
|
|
||||||
't' | 'l' => {
|
|
||||||
let mut v = vec![];
|
|
||||||
loop {
|
|
||||||
if stdout.one_byte().unwrap() == '\n' as u8 {
|
|
||||||
break if id_byte == 't' {
|
|
||||||
VDataEnum::Tuple(v)
|
|
||||||
} else {
|
|
||||||
VDataEnum::List(VType { types: vec![] }, v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
v.push(data_from_bytes(stdout).to())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'"' => {
|
|
||||||
let mut len_bytes = 0u64;
|
|
||||||
for _ in 0..8 {
|
|
||||||
len_bytes <<= 8;
|
|
||||||
len_bytes |= stdout.one_byte().unwrap() as u64;
|
|
||||||
}
|
|
||||||
let mut buf = Vec::with_capacity(len_bytes as _);
|
|
||||||
for _ in 0..len_bytes {
|
|
||||||
buf.push(stdout.one_byte().unwrap());
|
|
||||||
}
|
|
||||||
VDataEnum::String(String::from_utf8_lossy(&buf).into_owned())
|
|
||||||
}
|
|
||||||
'E' => {
|
|
||||||
let mut u = [0u8; 8];
|
|
||||||
stdout.read_exact(&mut u).unwrap();
|
|
||||||
let u = u64::from_be_bytes(u) as _;
|
|
||||||
VDataEnum::EnumVariant(u, Box::new(data_from_bytes(stdout).to()))
|
|
||||||
}
|
|
||||||
other => todo!("data_from_bytes: found '{other}'."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -119,7 +119,10 @@ fn normal_main() {
|
|||||||
std::process::exit(101);
|
std::process::exit(101);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parsing::file::File::new(std::fs::read_to_string(&args[0]).unwrap(), args[0].as_str().into())
|
parsing::file::File::new(
|
||||||
|
std::fs::read_to_string(&args[0]).unwrap(),
|
||||||
|
args[0].as_str().into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -219,7 +219,7 @@ pub fn parse_step_libs_load(
|
|||||||
let cmd_path = cmd.get_program().to_string_lossy().into_owned();
|
let cmd_path = cmd.get_program().to_string_lossy().into_owned();
|
||||||
match libs::Lib::launch(cmd, &mut ginfo.enum_variants) {
|
match libs::Lib::launch(cmd, &mut ginfo.enum_variants) {
|
||||||
Ok(lib) => {
|
Ok(lib) => {
|
||||||
for (i, (func, _, _)) in lib.registered_fns.iter().enumerate() {
|
for (i, (func, _)) in lib.registered_fns.iter().enumerate() {
|
||||||
ginfo.lib_fns.insert(func.clone(), (libs.len(), i));
|
ginfo.lib_fns.insert(func.clone(), (libs.len(), i));
|
||||||
}
|
}
|
||||||
libs.push(lib);
|
libs.push(lib);
|
||||||
|
@ -177,7 +177,7 @@ impl RStatementEnum {
|
|||||||
}
|
}
|
||||||
Self::BuiltinFunction(v, args) => v.run(args, vars, info),
|
Self::BuiltinFunction(v, args) => v.run(args, vars, info),
|
||||||
Self::LibFunction(libid, fnid, args, _) => info.libs[*libid]
|
Self::LibFunction(libid, fnid, args, _) => info.libs[*libid]
|
||||||
.run_fn(*fnid, &args.iter().map(|arg| arg.run(vars, info)).collect()),
|
.run_fn(*fnid, args.iter().map(|arg| arg.run(vars, info)).collect()),
|
||||||
Self::Block(b) => b.run(vars, info),
|
Self::Block(b) => b.run(vars, info),
|
||||||
Self::If(c, t, e) => {
|
Self::If(c, t, e) => {
|
||||||
if let VDataEnum::Bool(v) = c.run(vars, info).data {
|
if let VDataEnum::Bool(v) = c.run(vars, info).data {
|
||||||
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, sync::Arc};
|
|||||||
|
|
||||||
use crate::libs;
|
use crate::libs;
|
||||||
|
|
||||||
use super::{val_type::VType, builtins};
|
use super::{builtins, val_type::VType};
|
||||||
|
|
||||||
pub type GSInfo = Arc<GlobalScriptInfo>;
|
pub type GSInfo = Arc<GlobalScriptInfo>;
|
||||||
|
|
||||||
@ -44,4 +44,4 @@ impl GlobalScriptInfo {
|
|||||||
.map(|(i, v)| (v.to_string(), i))
|
.map(|(i, v)| (v.to_string(), i))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ use super::{
|
|||||||
builtins::BuiltinFunction,
|
builtins::BuiltinFunction,
|
||||||
code_macro::Macro,
|
code_macro::Macro,
|
||||||
code_parsed::{SBlock, SFunction, SStatement, SStatementEnum},
|
code_parsed::{SBlock, SFunction, SStatement, SStatementEnum},
|
||||||
code_runnable::{RBlock, RFunction, RScript, RStatement, RStatementEnum}, global_info::GSInfo,
|
code_runnable::{RBlock, RFunction, RScript, RStatement, RStatementEnum},
|
||||||
|
global_info::GSInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum ToRunnableError {
|
pub enum ToRunnableError {
|
||||||
@ -29,6 +30,7 @@ pub enum ToRunnableError {
|
|||||||
CannotDeclareVariableWithDereference(String),
|
CannotDeclareVariableWithDereference(String),
|
||||||
CannotDereferenceTypeNTimes(VType, usize, VType),
|
CannotDereferenceTypeNTimes(VType, usize, VType),
|
||||||
FunctionWrongArgCount(String, usize, usize),
|
FunctionWrongArgCount(String, usize, usize),
|
||||||
|
FunctionWrongArgs(Vec<VType>, String),
|
||||||
InvalidType {
|
InvalidType {
|
||||||
expected: VType,
|
expected: VType,
|
||||||
found: VType,
|
found: VType,
|
||||||
@ -56,7 +58,11 @@ impl Display for ToRunnableError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ToRunnableError {
|
impl ToRunnableError {
|
||||||
pub fn fmtgs(&self, f: &mut std::fmt::Formatter, info: Option<&GlobalScriptInfo>) -> std::fmt::Result {
|
pub fn fmtgs(
|
||||||
|
&self,
|
||||||
|
f: &mut std::fmt::Formatter,
|
||||||
|
info: Option<&GlobalScriptInfo>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::MainWrongInput => write!(
|
Self::MainWrongInput => write!(
|
||||||
f,
|
f,
|
||||||
@ -75,6 +81,7 @@ impl ToRunnableError {
|
|||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Self::FunctionWrongArgCount(v, a, b) => write!(f, "Tried to call function \"{v}\", which takes {a} arguments, with {b} arguments instead."),
|
Self::FunctionWrongArgCount(v, a, b) => write!(f, "Tried to call function \"{v}\", which takes {a} arguments, with {b} arguments instead."),
|
||||||
|
Self::FunctionWrongArgs(args, name) => write!(f, "Wrong args for function \"{name}\":{}", args.iter().map(|v| format!(" {v}")).collect::<String>()),
|
||||||
Self::InvalidType {
|
Self::InvalidType {
|
||||||
expected,
|
expected,
|
||||||
found,
|
found,
|
||||||
@ -146,7 +153,10 @@ struct LInfo {
|
|||||||
fns: HashMap<String, Arc<RFunction>>,
|
fns: HashMap<String, Arc<RFunction>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_runnable(s: SFunction, mut ginfo: GlobalScriptInfo) -> Result<RScript, (ToRunnableError, GSInfo)> {
|
pub fn to_runnable(
|
||||||
|
s: SFunction,
|
||||||
|
mut ginfo: GlobalScriptInfo,
|
||||||
|
) -> Result<RScript, (ToRunnableError, GSInfo)> {
|
||||||
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
if s.inputs.len() != 1 || s.inputs[0].0 != "args" {
|
||||||
return Err((ToRunnableError::MainWrongInput, ginfo.to_arc()));
|
return Err((ToRunnableError::MainWrongInput, ginfo.to_arc()));
|
||||||
}
|
}
|
||||||
@ -170,10 +180,7 @@ pub fn to_runnable(s: SFunction, mut ginfo: GlobalScriptInfo) -> Result<RScript,
|
|||||||
Err(e) => return Err((e, ginfo.to_arc())),
|
Err(e) => return Err((e, ginfo.to_arc())),
|
||||||
};
|
};
|
||||||
let ginfo = ginfo.to_arc();
|
let ginfo = ginfo.to_arc();
|
||||||
match RScript::new(
|
match RScript::new(func, ginfo.clone()) {
|
||||||
func,
|
|
||||||
ginfo.clone(),
|
|
||||||
) {
|
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(e) => Err((e, ginfo)),
|
Err(e) => Err((e, ginfo)),
|
||||||
}
|
}
|
||||||
@ -207,7 +214,10 @@ fn get_all_functions(
|
|||||||
vartype.to()
|
vartype.to()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.push((inputs.clone(), block(&s.block, ginfo, linfo.clone())?.out(ginfo)));
|
out.push((
|
||||||
|
inputs.clone(),
|
||||||
|
block(&s.block, ginfo, linfo.clone())?.out(ginfo),
|
||||||
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +259,11 @@ fn function(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(s: &SBlock, ginfo: &mut GlobalScriptInfo, mut linfo: LInfo) -> Result<RBlock, ToRunnableError> {
|
fn block(
|
||||||
|
s: &SBlock,
|
||||||
|
ginfo: &mut GlobalScriptInfo,
|
||||||
|
mut linfo: LInfo,
|
||||||
|
) -> Result<RBlock, ToRunnableError> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
for st in &s.statements {
|
for st in &s.statements {
|
||||||
statements.push(statement(st, ginfo, &mut linfo)?);
|
statements.push(statement(st, ginfo, &mut linfo)?);
|
||||||
@ -257,13 +271,13 @@ fn block(s: &SBlock, ginfo: &mut GlobalScriptInfo, mut linfo: LInfo) -> Result<R
|
|||||||
Ok(RBlock { statements })
|
Ok(RBlock { statements })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stypes(t: &mut VType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> {
|
pub fn stypes(t: &mut VType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> {
|
||||||
for t in &mut t.types {
|
for t in &mut t.types {
|
||||||
stype(t, ginfo)?;
|
stype(t, ginfo)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> {
|
pub fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunnableError> {
|
||||||
match t {
|
match t {
|
||||||
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String => (),
|
VSingleType::Bool | VSingleType::Int | VSingleType::Float | VSingleType::String => (),
|
||||||
VSingleType::Tuple(v) => {
|
VSingleType::Tuple(v) => {
|
||||||
@ -307,7 +321,7 @@ fn stype(t: &mut VSingleType, ginfo: &mut GlobalScriptInfo) -> Result<(), ToRunn
|
|||||||
return Err(ToRunnableError::UnknownType(name.to_owned()));
|
return Err(ToRunnableError::UnknownType(name.to_owned()));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
VSingleType::CustomType(_) => ()
|
VSingleType::CustomType(_) => (),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -342,28 +356,32 @@ fn statement(
|
|||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
rargs.push(statement(arg, ginfo, linfo)?);
|
rargs.push(statement(arg, ginfo, linfo)?);
|
||||||
}
|
}
|
||||||
if let Some(func) = linfo.fns.get(v) {
|
fn check_fn_args(args: &Vec<VType>, inputs: &Vec<(Vec<VType>, VType)>, ginfo: &GlobalScriptInfo) -> Option<VType> {
|
||||||
if rargs.len() != func.inputs.len() {
|
let mut fit_any = false;
|
||||||
return Err(ToRunnableError::FunctionWrongArgCount(
|
let mut out = VType::empty();
|
||||||
v.clone(),
|
for (inputs, output) in inputs {
|
||||||
func.inputs.len(),
|
if args.len() == inputs.len() && args.iter().zip(inputs.iter()).all(|(arg, input)| arg.fits_in(input, ginfo).is_empty()) {
|
||||||
rargs.len(),
|
fit_any = true;
|
||||||
));
|
out = out | output;
|
||||||
}
|
|
||||||
for (i, rarg) in rargs.iter().enumerate() {
|
|
||||||
let rarg = rarg.out(ginfo);
|
|
||||||
let out = rarg.fits_in(&func.input_types[i], ginfo);
|
|
||||||
if !out.is_empty() {
|
|
||||||
return Err(ToRunnableError::InvalidType {
|
|
||||||
expected: func.input_types[i].clone(),
|
|
||||||
found: rarg,
|
|
||||||
problematic: VType { types: out },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RStatementEnum::FunctionCall(func.clone(), rargs)
|
if fit_any {
|
||||||
|
Some(out)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let arg_types: Vec<_> = rargs.iter().map(|v| v.out(ginfo)).collect();
|
||||||
|
if let Some(func) = linfo.fns.get(v) {
|
||||||
|
if let Some(_out) = check_fn_args(&arg_types, &func.input_output_map.iter().map(|v| (v.0.iter().map(|v| v.clone().to()).collect(), v.1.to_owned())).collect(), ginfo) {
|
||||||
|
RStatementEnum::FunctionCall(func.clone(), rargs)
|
||||||
|
} else {
|
||||||
|
return Err(ToRunnableError::FunctionWrongArgs(
|
||||||
|
arg_types,
|
||||||
|
v.to_owned()
|
||||||
|
));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: type-checking for builtins
|
|
||||||
if let Some(builtin) = BuiltinFunction::get(v) {
|
if let Some(builtin) = BuiltinFunction::get(v) {
|
||||||
let arg_types = rargs.iter().map(|v| v.out(ginfo)).collect();
|
let arg_types = rargs.iter().map(|v| v.out(ginfo)).collect();
|
||||||
if builtin.can_take(&arg_types, ginfo) {
|
if builtin.can_take(&arg_types, ginfo) {
|
||||||
@ -374,16 +392,12 @@ fn statement(
|
|||||||
} else {
|
} else {
|
||||||
// LIBRARY FUNCTION?
|
// LIBRARY FUNCTION?
|
||||||
if let Some((libid, fnid)) = ginfo.lib_fns.get(v) {
|
if let Some((libid, fnid)) = ginfo.lib_fns.get(v) {
|
||||||
let (_name, fn_in, fn_out) = &ginfo.libs[*libid].registered_fns[*fnid];
|
let lib = &ginfo.libs[*libid];
|
||||||
if fn_in.len() == rargs.len() && fn_in.iter().zip(rargs.iter()).all(|(fn_in, arg)| arg.out(ginfo).fits_in(fn_in, ginfo).is_empty()) {
|
let libfn = &lib.registered_fns[*fnid];
|
||||||
|
if let Some(fn_out) = check_fn_args(&arg_types, &libfn.1, ginfo) {
|
||||||
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
|
RStatementEnum::LibFunction(*libid, *fnid, rargs, fn_out.clone())
|
||||||
} else {
|
} else {
|
||||||
// TODO! better error here
|
return Err(ToRunnableError::WrongArgsForLibFunction(v.to_owned(), arg_types));
|
||||||
return Err(if fn_in.len() == rargs.len() {
|
|
||||||
ToRunnableError::WrongArgsForLibFunction(v.to_string(), rargs.iter().map(|v| v.out(ginfo)).collect())
|
|
||||||
} else {
|
|
||||||
ToRunnableError::FunctionWrongArgCount(v.to_string(), fn_in.len(), rargs.len())
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(ToRunnableError::UseOfUndefinedFunction(v.clone()));
|
return Err(ToRunnableError::UseOfUndefinedFunction(v.clone()));
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
ops::BitOr,
|
ops::BitOr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::global_info::{GlobalScriptInfo, GSInfo, self};
|
use super::global_info::{self, GSInfo, GlobalScriptInfo};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct VType {
|
pub struct VType {
|
||||||
@ -39,18 +39,28 @@ impl VSingleType {
|
|||||||
Self::Reference(r) => r.get(i, gsinfo),
|
Self::Reference(r) => r.get(i, gsinfo),
|
||||||
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i, gsinfo),
|
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get(i, gsinfo),
|
||||||
Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo),
|
Self::CustomType(t) => gsinfo.custom_types[*t].get(i, gsinfo),
|
||||||
&Self::CustomTypeS(_) => unreachable!("CustomTypeS instead of CustomType, compiler bug? [get]"),
|
&Self::CustomTypeS(_) => {
|
||||||
|
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get]")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// None => might not always return t, Some(t) => can only return t
|
// None => might not always return t, Some(t) => can only return t
|
||||||
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
pub fn get_always(&self, i: usize, info: &GlobalScriptInfo) -> Option<VType> {
|
||||||
match self {
|
match self {
|
||||||
Self::Bool | Self::Int | Self::Float | Self::String | Self::List(_) | Self::Function(..) | Self::Thread(..) => None,
|
Self::Bool
|
||||||
|
| Self::Int
|
||||||
|
| Self::Float
|
||||||
|
| Self::String
|
||||||
|
| Self::List(_)
|
||||||
|
| Self::Function(..)
|
||||||
|
| Self::Thread(..) => None,
|
||||||
Self::Tuple(t) => t.get(i).cloned(),
|
Self::Tuple(t) => t.get(i).cloned(),
|
||||||
Self::Reference(r) => r.get_always(i, info),
|
Self::Reference(r) => r.get_always(i, info),
|
||||||
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get_always(i, info),
|
Self::EnumVariant(_, t) | Self::EnumVariantS(_, t) => t.get_always(i, info),
|
||||||
Self::CustomType(t) => info.custom_types[*t].get_always(i, info),
|
Self::CustomType(t) => info.custom_types[*t].get_always(i, info),
|
||||||
Self::CustomTypeS(_) => unreachable!("CustomTypeS instead of CustomType, compiler bug? [get_always]"),
|
Self::CustomTypeS(_) => {
|
||||||
|
unreachable!("CustomTypeS instead of CustomType, compiler bug? [get_always]")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -290,13 +300,23 @@ impl VSingleType {
|
|||||||
(Self::Reference(_), _) | (_, Self::Reference(_)) => false,
|
(Self::Reference(_), _) | (_, Self::Reference(_)) => false,
|
||||||
(Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => {
|
(Self::EnumVariant(v1, t1), Self::EnumVariant(v2, t2)) => {
|
||||||
*v1 == *v2 && t1.fits_in(&t2, info).is_empty()
|
*v1 == *v2 && t1.fits_in(&t2, info).is_empty()
|
||||||
},
|
}
|
||||||
(Self::CustomType(a), Self::CustomType(b)) => *a == *b /* || info.custom_types[*a].fits_in(&info.custom_types[*b], info).is_empty() */,
|
(Self::CustomType(a), Self::CustomType(b)) => *a == *b, /* || info.custom_types[*a].fits_in(&info.custom_types[*b], info).is_empty() */
|
||||||
(Self::CustomType(a), b) => info.custom_types[*a].fits_in(&b.clone().to(), info).is_empty(),
|
(Self::CustomType(a), b) => info.custom_types[*a]
|
||||||
(a, Self::CustomType(b)) => a.clone().to().fits_in(&info.custom_types[*b], info).is_empty(),
|
.fits_in(&b.clone().to(), info)
|
||||||
(Self::CustomTypeS(_), _) | (_, Self::CustomTypeS(_)) => unreachable!("CustomTypeS instead of CustomType - compiler bug?"),
|
.is_empty(),
|
||||||
|
(a, Self::CustomType(b)) => a
|
||||||
|
.clone()
|
||||||
|
.to()
|
||||||
|
.fits_in(&info.custom_types[*b], info)
|
||||||
|
.is_empty(),
|
||||||
|
(Self::CustomTypeS(_), _) | (_, Self::CustomTypeS(_)) => {
|
||||||
|
unreachable!("CustomTypeS instead of CustomType - compiler bug?")
|
||||||
|
}
|
||||||
(Self::EnumVariant(..), _) | (_, Self::EnumVariant(..)) => false,
|
(Self::EnumVariant(..), _) | (_, Self::EnumVariant(..)) => false,
|
||||||
(Self::EnumVariantS(..), _) | (_, Self::EnumVariantS(..)) => unreachable!("EnumVariantS instead of EnumVariant - compiler bug?"),
|
(Self::EnumVariantS(..), _) | (_, Self::EnumVariantS(..)) => {
|
||||||
|
unreachable!("EnumVariantS instead of EnumVariant - compiler bug?")
|
||||||
|
}
|
||||||
(Self::Bool, Self::Bool)
|
(Self::Bool, Self::Bool)
|
||||||
| (Self::Int, Self::Int)
|
| (Self::Int, Self::Int)
|
||||||
| (Self::Float, Self::Float)
|
| (Self::Float, Self::Float)
|
||||||
@ -304,7 +324,9 @@ impl VSingleType {
|
|||||||
(Self::Bool | Self::Int | Self::Float | Self::String, _) => false,
|
(Self::Bool | Self::Int | Self::Float | Self::String, _) => false,
|
||||||
(Self::Tuple(a), Self::Tuple(b)) => {
|
(Self::Tuple(a), Self::Tuple(b)) => {
|
||||||
if a.len() == b.len() {
|
if a.len() == b.len() {
|
||||||
a.iter().zip(b.iter()).all(|(a, b)| a.fits_in(b, info).is_empty())
|
a.iter()
|
||||||
|
.zip(b.iter())
|
||||||
|
.all(|(a, b)| a.fits_in(b, info).is_empty())
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -338,7 +360,15 @@ impl VSingleType {
|
|||||||
}
|
}
|
||||||
pub fn fits_in_type(&self, rhs: &VType, info: &GlobalScriptInfo) -> bool {
|
pub fn fits_in_type(&self, rhs: &VType, info: &GlobalScriptInfo) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::CustomType(t) => rhs.types.iter().any(|rhs| if let Self::CustomType(rhs) = rhs { *t == *rhs } else { false }) || info.custom_types[*t].fits_in(rhs, info).is_empty(),
|
Self::CustomType(t) => {
|
||||||
|
rhs.types.iter().any(|rhs| {
|
||||||
|
if let Self::CustomType(rhs) = rhs {
|
||||||
|
*t == *rhs
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) || info.custom_types[*t].fits_in(rhs, info).is_empty()
|
||||||
|
}
|
||||||
_ => rhs.types.iter().any(|t| self.fits_in(t, info)),
|
_ => rhs.types.iter().any(|t| self.fits_in(t, info)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,9 +440,13 @@ impl VSingleType {
|
|||||||
}
|
}
|
||||||
Self::EnumVariant(variant, inner) => {
|
Self::EnumVariant(variant, inner) => {
|
||||||
if let Some(name) = if let Some(info) = info {
|
if let Some(name) = if let Some(info) = info {
|
||||||
info.enum_variants
|
info.enum_variants.iter().find_map(|(name, id)| {
|
||||||
.iter()
|
if id == variant {
|
||||||
.find_map(|(name, id)| if id == variant { Some(name) } else { None })
|
Some(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
} {
|
} {
|
||||||
@ -428,14 +462,39 @@ impl VSingleType {
|
|||||||
inner.fmtgs(f, info)?;
|
inner.fmtgs(f, info)?;
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Self::CustomType(t) => if let Some(info) = info {
|
Self::CustomType(t) => {
|
||||||
#[cfg(not(debug_assertions))]
|
if let Some(info) = info {
|
||||||
write!(f, "{}", info.custom_type_names.iter().find_map(|(name, id)| if *t == *id { Some(name.to_owned()) } else { None }).unwrap())?;
|
#[cfg(not(debug_assertions))]
|
||||||
#[cfg(debug_assertions)]
|
write!(
|
||||||
write!(f, "{}/*{}*/", info.custom_type_names.iter().find_map(|(name, id)| if *t == *id { Some(name.to_owned()) } else { None }).unwrap(), &info.custom_types[*t])?;
|
f,
|
||||||
Ok(())
|
"{}",
|
||||||
} else {
|
info.custom_type_names
|
||||||
write!(f, "[custom type #{t}]")
|
.iter()
|
||||||
|
.find_map(|(name, id)| if *t == *id {
|
||||||
|
Some(name.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
)?;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}/*{}*/",
|
||||||
|
info.custom_type_names
|
||||||
|
.iter()
|
||||||
|
.find_map(|(name, id)| if *t == *id {
|
||||||
|
Some(name.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
&info.custom_types[*t]
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
write!(f, "[custom type #{t}]")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Self::CustomTypeS(t) => write!(f, "{t}"),
|
Self::CustomTypeS(t) => write!(f, "{t}"),
|
||||||
}
|
}
|
||||||
|
34
mers/tests/lib_comms.rs
Normal file
34
mers/tests/lib_comms.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use mers_libs::prelude::*;
|
||||||
|
use mers_libs::{ByteData, ByteDataA};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_type() {
|
||||||
|
let a: Vec<i32> = vec![14, 26];
|
||||||
|
let bytes = a.as_byte_data_vec();
|
||||||
|
println!("{bytes:?}");
|
||||||
|
assert_eq!(
|
||||||
|
Vec::<i32>::from_byte_data(&mut Cursor::new(bytes)).unwrap(),
|
||||||
|
a
|
||||||
|
);
|
||||||
|
|
||||||
|
let a = VSingleType::List(VSingleType::Int.to()).to();
|
||||||
|
assert_eq!(
|
||||||
|
VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())).unwrap(),
|
||||||
|
a
|
||||||
|
);
|
||||||
|
|
||||||
|
let a = VSingleType::Tuple(vec![
|
||||||
|
VType {
|
||||||
|
types: vec![VSingleType::Tuple(vec![]), VSingleType::Int],
|
||||||
|
},
|
||||||
|
VSingleType::String.to(),
|
||||||
|
VSingleType::EnumVariant(12, VSingleType::Float.to()).to(),
|
||||||
|
])
|
||||||
|
.to();
|
||||||
|
assert_eq!(
|
||||||
|
VType::from_byte_data(&mut Cursor::new(a.as_byte_data_vec())).unwrap(),
|
||||||
|
a
|
||||||
|
);
|
||||||
|
}
|
@ -1,89 +1,139 @@
|
|||||||
use mers_libs::{MyLib, MyLibTask, VDataEnum, VSingleType, VType};
|
use mers_libs::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (mut my_lib, mut run) = MyLib::new(
|
let mut my_lib = MyLib::new(
|
||||||
"HTTP requests for MERS".to_string(),
|
"http".to_string(), // "HTTP requests for MERS".to_string(),
|
||||||
(0, 0),
|
(0, 0),
|
||||||
"basic HTTP functionality for mers. warning: this is fully single-threaded.".to_string(),
|
"desc".to_string(), // "basic HTTP functionality for mers. warning: this is fully single-threaded.".to_string(),
|
||||||
vec![(
|
vec![
|
||||||
"http_get".to_string(),
|
// http_get
|
||||||
vec![VSingleType::String.to()],
|
(
|
||||||
VType {
|
"http_get".to_string(),
|
||||||
types: vec![
|
vec![
|
||||||
VSingleType::String,
|
// (String) -> String/Err(ErrBuildingRequest(String)/ErrGettingResponseText(String))
|
||||||
VSingleType::EnumVariantS(
|
(
|
||||||
format!("Err"),
|
vec![VSingleType::String.to()],
|
||||||
VType {
|
VType {
|
||||||
types: vec![
|
types: vec![
|
||||||
|
VSingleType::String,
|
||||||
VSingleType::EnumVariantS(
|
VSingleType::EnumVariantS(
|
||||||
format!("ErrBuildingRequest"),
|
format!("Err"),
|
||||||
VSingleType::String.to(),
|
VType {
|
||||||
),
|
types: vec![
|
||||||
VSingleType::EnumVariantS(
|
VSingleType::EnumVariantS(
|
||||||
format!("ErrGettingResponseText"),
|
format!("ErrBuildingRequest"),
|
||||||
VSingleType::String.to(),
|
VSingleType::String.to(),
|
||||||
|
),
|
||||||
|
VSingleType::EnumVariantS(
|
||||||
|
format!("ErrGettingResponseText"),
|
||||||
|
VSingleType::String.to(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
),
|
||||||
)],
|
],
|
||||||
);
|
);
|
||||||
let mut stdin = std::io::stdin().lock();
|
let err_general = my_lib
|
||||||
let mut stdout = std::io::stdout().lock();
|
.get_enums()
|
||||||
let mut err_general = 0;
|
.iter()
|
||||||
let mut err_building_request = 0;
|
.find(|(name, _)| name.as_str() == "Err")
|
||||||
let mut err_getting_response_text = 0;
|
.unwrap()
|
||||||
loop {
|
.1;
|
||||||
run = match my_lib.run(run, &mut stdin, &mut stdout) {
|
let err_building_request = my_lib
|
||||||
MyLibTask::None(v) => v,
|
.get_enums()
|
||||||
MyLibTask::FinishedInit(v) => {
|
.iter()
|
||||||
err_general = my_lib.get_enum("Err").unwrap();
|
.find(|(name, _)| name.as_str() == "ErrBuildingRequest")
|
||||||
err_building_request = my_lib.get_enum("ErrBuildingRequest").unwrap();
|
.unwrap()
|
||||||
err_getting_response_text = my_lib.get_enum("ErrGettingResponseText").unwrap();
|
.1;
|
||||||
v
|
let err_getting_response_text = my_lib
|
||||||
}
|
.get_enums()
|
||||||
MyLibTask::RunFunction(f) => {
|
.iter()
|
||||||
let return_value = match f.function {
|
.find(|(name, _)| name.as_str() == "ErrGettingResponseText")
|
||||||
0 => {
|
.unwrap()
|
||||||
// http_get
|
.1;
|
||||||
if let VDataEnum::String(url) = &f.args[0].data {
|
my_lib.callbacks.run_function.consuming = Some(Box::new(move |msg| {
|
||||||
match reqwest::blocking::get(url) {
|
if let VDataEnum::String(url) = &msg.msg.args[0].data {
|
||||||
Ok(response) => match response.text() {
|
let url = url.clone();
|
||||||
Ok(text) => VDataEnum::String(text).to(),
|
std::thread::spawn(move || {
|
||||||
Err(e) => VDataEnum::EnumVariant(
|
let r = match reqwest::blocking::get(url) {
|
||||||
err_general,
|
Ok(response) => match response.text() {
|
||||||
Box::new(
|
Ok(text) => VDataEnum::String(text).to(),
|
||||||
VDataEnum::EnumVariant(
|
Err(e) => VDataEnum::EnumVariant(
|
||||||
err_getting_response_text,
|
err_general,
|
||||||
Box::new(VDataEnum::String(e.to_string()).to()),
|
Box::new(
|
||||||
)
|
VDataEnum::EnumVariant(
|
||||||
.to(),
|
err_getting_response_text,
|
||||||
),
|
Box::new(VDataEnum::String(e.to_string()).to()),
|
||||||
)
|
|
||||||
.to(),
|
|
||||||
},
|
|
||||||
Err(e) => VDataEnum::EnumVariant(
|
|
||||||
err_general,
|
|
||||||
Box::new(
|
|
||||||
VDataEnum::EnumVariant(
|
|
||||||
err_building_request,
|
|
||||||
Box::new(VDataEnum::String(e.to_string()).to()),
|
|
||||||
)
|
|
||||||
.to(),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.to(),
|
.to(),
|
||||||
}
|
),
|
||||||
} else {
|
)
|
||||||
unreachable!()
|
.to(),
|
||||||
}
|
},
|
||||||
}
|
Err(e) => VDataEnum::EnumVariant(
|
||||||
_ => unreachable!(),
|
err_general,
|
||||||
|
Box::new(
|
||||||
|
VDataEnum::EnumVariant(
|
||||||
|
err_building_request,
|
||||||
|
Box::new(VDataEnum::String(e.to_string()).to()),
|
||||||
|
)
|
||||||
|
.to(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.to(),
|
||||||
};
|
};
|
||||||
f.done(&mut stdout, return_value)
|
msg.respond(r)
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
|
// because we handle all callbacks, this never returns Err(unhandeled message).
|
||||||
|
// it returns Ok(()) if mers exits (i/o error in stdin/stdout), so we also exit if that happens.
|
||||||
|
my_lib.get_next_unhandled_message().unwrap();
|
||||||
}
|
}
|
||||||
|
// fn run_function(f: ()) {
|
||||||
|
// let return_value = match f.function {
|
||||||
|
// 0 => {
|
||||||
|
// // http_get
|
||||||
|
// if let VDataEnum::String(url) = &f.args[0].data {
|
||||||
|
// match reqwest::blocking::get(url) {
|
||||||
|
// Ok(response) => match response.text() {
|
||||||
|
// Ok(text) => VDataEnum::String(text).to(),
|
||||||
|
// Err(e) => VDataEnum::EnumVariant(
|
||||||
|
// err_general,
|
||||||
|
// Box::new(
|
||||||
|
// VDataEnum::EnumVariant(
|
||||||
|
// err_getting_response_text,
|
||||||
|
// Box::new(VDataEnum::String(e.to_string()).to()),
|
||||||
|
// )
|
||||||
|
// .to(),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// .to(),
|
||||||
|
// },
|
||||||
|
// Err(e) => VDataEnum::EnumVariant(
|
||||||
|
// err_general,
|
||||||
|
// Box::new(
|
||||||
|
// VDataEnum::EnumVariant(
|
||||||
|
// err_building_request,
|
||||||
|
// Box::new(VDataEnum::String(e.to_string()).to()),
|
||||||
|
// )
|
||||||
|
// .to(),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
// .to(),
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// unreachable!()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// };
|
||||||
|
// f.done(&mut stdout, return_value)
|
||||||
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user