diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 2808a0b..2af77d0 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,8 @@ { "recommendations": [ "swellaby.vscode-rust-test-adapter", - "nyxiative.rust-and-friends" + "nyxiative.rust-and-friends", + "itsyaasir.rust-feature-toggler", + "rust-lang.rust-analyzer" ] } \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..dd63ce2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,64 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug级单元测试", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=babel_nar" + ], + "filter": { + "name": "babel_nar", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug可执行文件「CIN启动器」", + "cargo": { + "args": [ + "build", + "--bin=cin_launcher", + "--package=babel_nar" + ], + "filter": { + "name": "cin_launcher", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug级单元测试「CIN启动器」", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=cin_launcher", + "--package=babel_nar" + ], + "filter": { + "name": "cin_launcher", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d06b245 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "rust-analyzer.cargo.features": "all", + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e260f4d..dafbd0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,34 @@ version = 3 [[package]] name = "babel_nar" version = "0.1.0" +dependencies = [ + "nar_dev_utils", + "narsese", + "navm", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "nar_dev_utils" +version = "0.12.0" + +[[package]] +name = "narsese" +version = "0.5.0" +dependencies = [ + "lazy_static", + "nar_dev_utils", +] + +[[package]] +name = "navm" +version = "0.1.0" +dependencies = [ + "nar_dev_utils", + "narsese", +] diff --git a/Cargo.toml b/Cargo.toml index 536ef43..12a95c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,34 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] + +[dependencies.nar_dev_utils] +# 【2024-03-13 21:17:55】实用库现在独立为`nar_dev_utils` +# version = "0.1.0" # ! 本地依赖可以不添加版本 +# *🚩【2024-03-21 09:26:38】启用所有 +path = "../NAR-dev-util" +features = [] + +[dependencies.narsese] +# ! 本地依赖可以不添加版本 +# 载入Narsese API,引入其中所有部分 +path = "../Narsese.rs" +features = ["bundled"] + +[dependencies.navm] +# ! 本地依赖可以不添加版本 +# 载入NAVM API,引入「非公理虚拟机」模型 +path = "../NAVM.rs" +features = [] # ! 【2024-03-21 09:24:51】暂时没有特性 + +# 定义库的特性 +[features] +# 默认启用的特性 +default = [] +# 大杂烩 +bundled = [ + "implements" +] +# 各个独立的特性 # +# 具体接口实现:OpenNARS、ONA、NARS-Python、OpenJunars、PyNARS…… +implements = [] diff --git a/README.md b/README.md index 8c7134b..81dd3ad 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,11 @@ 该项目使用[语义化版本 2.0.0](https://semver.org/)进行版本号管理。 -基于[**NAVM.rs**](https://github.com/ARCJ137442/NAVM.rs)的CIN(NARS计算机实现)接口 +[**NAVM.rs**](https://github.com/ARCJ137442/NAVM.rs)的**运行时** - 前身为[**BabelNAR.jl**](https://github.com/ARCJ137442/BabelNAR.jl) -- 旨在方便连接各类CIN,并通过**Websocket**等服务提供**通用统一交互接口**。 +- 🎯为「非公理虚拟机模型」提供程序实现 +- 🎯为各CIN实现**统一输入输出**形式 ## 概念 diff --git a/src/impl_runtime/mod.rs b/src/impl_runtime/mod.rs new file mode 100644 index 0000000..7c8740d --- /dev/null +++ b/src/impl_runtime/mod.rs @@ -0,0 +1,2 @@ +//! 对各CIN实现「非公理虚拟机」模型 +//! * 🎯基于「NAVM指令/NAVM输出↔字符串」的转换 diff --git a/src/lib.rs b/src/lib.rs index a30abec..76230fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,21 @@ //! 主模块 -//! TODO: 参照**BabelNAR.jl**迁移并完善代码 +//! * ✨进程IO库 +//! * ✨通用运行时 +//! * ✨运行时的各类实现(可选) + +// 实用库别名 +pub extern crate nar_dev_utils as util; + +// 必选模块 +util::pub_mod_and_pub_use! { + // 进程IO + process_io + // 运行时 + runtime +} + +// 可选模块 +util::feature_pub_mod_and_reexport!{ + // 运行时实现 + "implements" => impl_runtime +} \ No newline at end of file diff --git a/src/process_io/mod.rs b/src/process_io/mod.rs new file mode 100644 index 0000000..935f3ac --- /dev/null +++ b/src/process_io/mod.rs @@ -0,0 +1,167 @@ +//! 用于封装抽象「进程通信」逻辑 +//! 示例代码来源:https://www.nikbrendler.com/rust-process-communication/ +//! * 📌基于「通道」的「子进程+专职读写的子线程」通信逻辑 +//! +//! TODO: 封装抽象提取 + +#![allow(unused)] + +use std::ffi::OsStr; +use std::io::{BufRead, BufReader, Write}; +use std::process::{ChildStdin, ChildStdout, Command, Stdio}; +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::Mutex; +use std::thread; +use std::thread::sleep; +use std::time::Duration; + +fn sleep_secs(secs: u64) { + sleep(Duration::from_secs(secs)); +} + +/// 启动子进程 +fn start_process>( + program_path: S, + sender: Sender, + receiver: Receiver, +) { + // 创建一个子进程 + let child = + // 指令+参数 + Command::new(program_path) + .arg("shell") + // 输入输出 + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + // 产生进程 + .spawn() + .expect("Failed to start process"); + + println!("Started process: {}", child.id()); + + let stdin = child.stdin.unwrap(); + let stdout = child.stdout.unwrap(); + /// 生成进程的「读写守护」(线程) + let thread_write_in = spawn_thread_write_in(stdin, receiver); + let thread_read_out = spawn_thread_read_out(stdout, sender); +} + +/// 生成一个子线程,管理子进程的标准输入,接收通道另一端输出 +/// * 📌读输入,写进程 +fn spawn_thread_write_in(stdin: ChildStdin, receiver: Receiver) -> thread::JoinHandle<()> { + thread::spawn(move || { + // 从通道接收者读取输入 | 从「进程消息发送者」向进程发送文本 + let mut stdin = stdin; + for line in receiver { + // 写入输出 + if let Err(e) = stdin.write_all(line.as_bytes()) { + println!("无法向子进程输入:{e:?}"); + } + } + }) +} + +/// 生成一个子线程,管理子进程的标准输出,传送输出的消息到另一端 +/// * 📌写输出 +fn spawn_thread_read_out(stdout: ChildStdout, sender: Sender) -> thread::JoinHandle<()> { + thread::spawn(move || { + // 读取输出 + let mut stdout_reader = BufReader::new(stdout); + // 持续循环 + loop { + // 从子进程「标准输出」读取输入 + let mut buf = String::new(); + match stdout_reader.read_line(&mut buf) { + // 没有任何输入⇒跳过 + Ok(0) => continue, + // 有效输入 + Ok(_) => { + println!("子进程输出: {buf:?}"); + // 向「进程消息接收者」传递消息(实际上是「输出」) + if let Err(e) = sender.send(buf) { + println!("无法接收子进程输出:{e:?}"); + break; + } + continue; + } + Err(e) => { + println!("子进程报错: {:?}", e); + break; + } + } + } + }) +} + +fn start_command_thread(mutex: Mutex>) { + // 生成一个子线程,对上述进程进行读取 + thread::spawn(move || { + let sender = mutex.lock().unwrap(); + // 测试输入输出 + sleep_secs(1); + sender.send(" B>.\n".into()).unwrap(); + sleep_secs(1); + sender.send(" C>.\n".into()).unwrap(); + sleep_secs(1); + sender.send(" C>?\n".into()).unwrap(); + sleep_secs(1); + }); +} + +/// 单元测试 +#[cfg(test)] +mod tests { + use super::*; + + // 定义一系列路径 + const EXE_PATH_ONA: &str = r"..\..\NARS-executables\NAR.exe"; + const EXE_PATH_REPL: &str = r"..\..\..\Julia\语言学小工Ju\繁简转换\dist\repl_简化.exe"; + const EXE_PATH_ECHO: &str = r"..\NAVM.rs\target\debug\examples\echo_exe.exe"; + + /// 实验用测试 + #[test] + fn test() { + // 创建通道 + let (child_out, out_sender) = channel(); + let (in_receiver, child_in) = channel(); + + // 启动进程 + start_process(EXE_PATH_ONA, child_out, child_in); + + // tx2.send(("Command 1\n".into())).unwrap(); + let mutex = Mutex::new(in_receiver); + start_command_thread(mutex); + // println!("{in_receiver:?}"); + + // 从外部获取输出(阻塞) + // for line in out_sender { + // println!("Got this back: {}", line); + // } + + // 等待 + sleep_secs(5); + println!("程序结束!"); + } + + /// 标准案例:ONA交互 + /// + /// ## 测试输入 + /// + /// ```plaintext + /// B>. + /// C>. + /// C>? + /// ``` + /// + /// ## 预期输出 + /// + /// ```plaintext + /// Answer: C>. creationTime=2 Truth: frequency=1.000000, confidence=0.810000 + /// ``` + /// + /// TODO: 【2024-03-21 10:02:34】按想要的「目标形式」写测试,然后以此驱动开发整个库(面向用法) + #[test] + fn test_ona() { + // let runtime = Runtime::builder(); + } +} diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs new file mode 100644 index 0000000..7886f5d --- /dev/null +++ b/src/runtime/mod.rs @@ -0,0 +1 @@ +//! 用于封装表示「非公理虚拟机」运行时