Capabilities and frames
รอยต่อระหว่าง Faber กับทุกวิธีที่ระบบปฏิบัติการสามารถใช้เพื่อทำ I/O ได้
ถึง คือ primitive สำหรับเรียกใช้ความสามารถระดับต่ำของ Faber ซึ่งเป็นขอบเขต
ระหว่างโค้ด Faber กับโลกภายนอก โดยจะเปิดบทสนทนาแบบมีชนิดข้อมูล
(ช่องทาง) กับทรัพยากรของโฮสต์ที่ระบุด้วยสตริงเส้นทาง จากนั้นแลกเปลี่ยน
เฟรมที่มีโครงสร้าง (เฟรม) ผ่านสตรีมย่อยแบบกำหนดทิศทาง
เคอร์เนลของโฮสต์จะส่งแต่ละเส้นทางไปยัง crate ผู้ให้บริการที่ถอดเปลี่ยนได้
ซึ่งเป็นผู้ทำ I/O จริง เช่น ระบบไฟล์ เครือข่าย คอนโซล เวลา ความสุ่ม
หรือสิ่งอื่นใดที่ระบบปฏิบัติการทำได้
primitive ถึง#
ถึง เป็นคีย์เวิร์ด ไม่ใช่ฟังก์ชัน โดยจะเปิดบทสนทนาแบบทึบแสง
ด้วยเส้นทางที่ระบุด้วยลิเทอรัล ascii และข้อมูลสำหรับเปิดที่เป็นตัวเลือก:
# Simple materialized call: open, send opener, drain response
คงที่ ข้อความ content ← ถึง 'solum:lege' ("config.toml") ↦ ข้อความ
# Typed conversation handle for streaming interaction
คงที่ ช่องทาง s ← ถึง 'processus:curre' ("ls", ["-la"])สตริงเส้นทางใช้รูปแบบ prefix:verb เคอร์เนลของโฮสต์จะจับคู่เฉพาะ
prefix เท่านั้น ส่วนผู้ให้บริการจะเป็นเจ้าของ verb ทั้งหมดภายใต้ prefix นั้น:
solum:lege ─┐
solum:modum ─┼─► prefix "solum" ──► เฉพาะ provider crate
solum:vincula─┘ถึง ไม่ใช่อินเทอร์เฟซสำหรับเรียกใช้ฟังก์ชันภายนอก ไม่ได้เรียกฟังก์ชัน C
โหลดไลบรารีแบบไดนามิก หรือฝังแอสเซมบลีแบบอินไลน์ แต่เป็นขอบเขตการส่ง
ข้อความที่มีโครงสร้าง: Faber ส่งเฟรมที่มีชนิดข้อมูลและรับเฟรมที่มีชนิดข้อมูล
โดยไม่จำเป็นต้องรู้ว่าผู้ให้บริการเขียนด้วย Rust ทำงานอยู่ในโปรเซสเดียวกัน
ส่งต่อไปยัง system call หรือส่งต่อไปยังโฮสต์ระยะไกล
ชนิดของเฟรม#
ชนิดข้อมูลห้าชนิดที่คอมไพเลอร์เป็นเจ้าของประกอบกันเป็นระบบเฟรม:
| ชนิด | บทบาท | ส่วนสำคัญ |
|---|---|---|
ช่องทาง | แฮนเดิลบทสนทนา — การแลกเปลี่ยนสองทิศทางที่กำลังทำงานอยู่ | สร้างโดย ถึง; ระบายผ่าน ↦ T หรือแยกเป็นมุมมอง |
เฟรม<T> | กล่องหุ้มเฟรม — ข้อความที่มีโครงสร้างหนึ่งข้อความในบทสนทนา | ฟิลด์: id, call, status, data, created_ms, from, trace |
status | enum ที่ระบุสถานะวงจรชีวิต | request, item, byte, bulk, done, error, cancel |
ส่ง<T> | สตรีมย่อยขาออก — ส่งเฟรมไปยังผู้ให้บริการ | da(T), fini() → status |
รับ<T> | สตรีมย่อยขาเข้า — รับเฟรมจากผู้ให้บริการ | accipe(), เคอร์เซอร์(), exhauri(), fini() |
การใช้มุมมองแบบกำหนดทิศทาง#
# Open a conversation, get directional views
คงที่ ช่องทาง s ← ถึง 'solum:scribe' ("output.txt")
คงที่ ส่ง<ข้อความ> out ← s.meus<ข้อความ>()
คงที่ รับ<ข้อความ> input ← s.tuus<ข้อความ>()
# Send content frames
out.da("line one")
out.da("line two")
out.fini()
# Read response frames
วน ออก input.cursor() คงที่ frame {
บันทึก frame.data
}
คงที่ status inbound ← input.fini()การทำให้เป็นค่าทั่วไป#
สำหรับกรณีทั่วไป — เปิด ส่งข้อมูลสำหรับเปิด และระบายเฟรมตอบกลับทั้งหมด
ลงในค่าเดียว — ช่องทาง ↦ T จะรวมบทสนทนาให้เสร็จในขั้นตอนเดียว:
# Read a file: open + drain into ข้อความ
คงที่ ข้อความ body ← ถึง 'solum:lege' ("config.toml") ↦ ข้อความ
# Parse JSON from an HTTP response
คงที่ json data ← ถึง 'http:peti' ("https://api.example.com/data") ↦ jsonการทำให้เป็นค่าใช้ตัวรวบรวมที่กำหนดตามชนิดข้อมูล: ↦ ข้อความ
จะนำเฟรมขาเข้าทั้งหมดมาต่อกัน, ↦ json จะแยกวิเคราะห์ payload
ที่ต่อกันแล้ว, ส่วน ↦ รายการ<T> จะรวบรวมเฟรมเป็นรายการ
ผู้ให้บริการของโฮสต์#
กลุ่มผลกระทบถูกนำไปใช้งานเป็น crate ผู้ให้บริการแยกกันภายใต้
faberlang/host-providers-rs ผู้ให้บริการแต่ละรายเป็นเจ้าของ verb ทั้งหมด
ภายใต้ prefix ของตน:
| ผู้ให้บริการ | Prefix | ขอบเขต I/O |
|---|---|---|
เฉพาะ | เฉพาะ:* | ระบบไฟล์: อ่าน เขียน เมทาดาทา และการดำเนินการกับไดเรกทอรี |
processus | processus:* | การเรียกใช้โปรเซส: สร้าง เชื่อม pipe และรหัสการออก |
consolum | consolum:* | I/O ของคอนโซล: stdin, stdout, stderr |
tempus | tempus:* | เวลา: เวลาปัจจุบัน การหยุดรอ และตัวจับเวลา |
aleator | aleator:* | ความสุ่ม: เอนโทรปี และการแจกแจง |
http | http:* | ไคลเอนต์ HTTP (Tier D เมื่อรวมเข้าระบบแล้ว) |
ผู้ให้บริการเป็น crate แยกกันและมี dependency ของตนเอง — เฉพาะ
จะไม่ดึง HTTP เข้ามา และ http จะไม่ดึงโค้ดระบบไฟล์เข้ามา
ผู้ให้บริการแต่ละรายส่งออกฟังก์ชัน register() ซึ่ง manifest ของโฮสต์
ที่สร้างขึ้นจะเรียกใช้เมื่อเริ่มต้นระบบ
ชั้นสถาปัตยกรรม#
Faber source: ถึง 'solum:lege' (path) ↦ ข้อความ
Compiler: ช่องทาง open + generic attach (no provider crate names)
Runtime: HostDispatch + conversation protocol (faber-runtime)
Kernel: route(frame) → provider for prefix
Provider: เฉพาะ provider reads file, returns contentคอมไพเลอร์จะสร้างโค้ด dispatch แบบทั่วไปเท่านั้น — จะไม่ฝังชื่อ crate
ผู้ให้บริการลงในโค้ดที่สร้างขึ้น รันไทม์จะจัดเตรียม HostDispatch
และโพรโทคอลของบทสนทนา เคอร์เนล (จาก host-kernel-rs) จะส่งเฟรม
ไปยังผู้ให้บริการที่ถูกต้องโดยพิจารณาจาก prefix ผู้ให้บริการ
(จาก host-providers-rs) จะทำ I/O จริง
ดังนั้นโค้ด Faber ที่สร้างขึ้นจึง ไม่ผูกกับผู้ให้บริการ ไบนารีที่คอมไพล์แล้วเดียวกันสามารถลิงก์กับการใช้งานผู้ให้บริการที่ต่างกันได้ เช่น ผู้ให้บริการระบบไฟล์จริงสำหรับการใช้งานจริง หรือผู้ให้บริการจำลอง สำหรับการทดสอบ โดยเปลี่ยน compile manifest
แมนิเฟสต์คอมไพล์#
ผู้ให้บริการที่จะลิงก์จะถูกควบคุมโดย compile manifest ที่สร้างขึ้น
และตาราง [dispatch] ใน faber.toml:
[target.rust]
host = "native"
[dispatch]
providers = ["solum", "processus", "consolum", "tempus", "aleator"]
[dispatch.providers.http]
enabled = trueระหว่างการเขียนโปรแกรม หากไม่มีผู้ให้บริการ ระบบจะส่งคืนข้อผิดพลาดรันไทม์
E_NO_ROUTE ในโหมด strict (ในอนาคต) ทุก prefix ของ ถึง ในโปรแกรม
ต้องปรากฏอยู่ใน compile manifest และคอมไพเลอร์จะตรวจสอบว่า capability
manifest ของผู้ให้บริการครอบคลุมเส้นทางที่ใช้งานหรือไม่
สถาปัตยกรรม#
แพลตฟอร์มโฮสต์แบ่งออกเป็นสาม repository ในองค์กร
faberlang:
| Repository | บทบาท |
|---|---|
host-kernel-rs | เราเตอร์ขนาดเล็ก — เป็นเจ้าของ Frame, Conversation, วงจรชีวิตช่วงสิ้นสุด, การ dispatch ตาม prefix, ข้อผิดพลาดที่มีโครงสร้าง (E_NO_ROUTE) และการรวม capability manifest |
host-native-rs | การเชื่อมต่อแบบ native — worker, hook เริ่มต้น register_providers และการผนวกรวม host_register.rs ที่สร้างขึ้น |
host-providers-rs | การใช้งานผู้ให้บริการ — Cargo workspace ที่มี crate แยกตามกลุ่ม (เฉพาะ, processus เป็นต้น) |
crate ผู้ให้บริการแต่ละรายเป็นเจ้าของ dependency แบบ native ของตนเอง
ผู้ให้บริการ http จะดึง hyper และ tokio เข้ามาเฉพาะเมื่อเปิดใช้ HTTP
ส่วนผู้ให้บริการ เฉพาะ ใช้ API ไฟล์มาตรฐานโดยไม่มี dependency
ด้านเครือข่ายเพิ่มเติม
เส้นทางเดียวกัน ใช้ได้กับทุกโฮสต์ เนื่องจาก
ถึงdispatch ด้วยสตริงเส้นทางและผู้ให้บริการสามารถถอดเปลี่ยนได้ ซอร์ส Faber เดียวกัน จึงสามารถกำหนดเป้าหมายเป็นไบนารี native (host-native-rs), รันไทม์ WASM (เคอร์เนลโฮสต์ในฐานะอะแดปเตอร์ Frame/Wasm) หรือโปรเซส TypeScript Node.js (host-providers-ts) ได้โดยไม่ต้องเปลี่ยนโค้ด Faber แม้แต่บรรทัดเดียว
ตัวห่อหุ้มของ Norma#
โค้ด Faber ส่วนใหญ่ไม่ได้เรียก ถึง โดยตรง ไลบรารีมาตรฐาน Norma
จะห่อหุ้มเส้นทาง ถึง ที่ใช้ทั่วไปไว้ในฟังก์ชันที่มีชนิดข้อมูล:
# Norma wraps ถึง in typed, reviewed functions
ฟังก์ชัน อ่าน(ข้อความ ผ่านทาง) → ข้อความ {
คืน ถึง 'solum:lege' (ผ่านทาง) ↦ ข้อความ
}
ฟังก์ชัน เขียน(ข้อความ ผ่านทาง, ข้อความ content) → เปล่า {
คงที่ เปล่า _ ← ถึง 'solum:scribe' (ผ่านทาง, content) ↦ เปล่า
}
ฟังก์ชัน curre(ข้อความ command, รายการ<ข้อความ> args) → ข้อความ {
คืน ถึง 'processus:curre' (command, args) ↦ ข้อความ
}ฟังก์ชันตัวห่อหุ้มเหล่านี้ให้ความปลอดภัยด้านชนิดข้อมูล เอกสารประกอบ
และการจัดการข้อผิดพลาด โดยไม่ซ่อนข้อเท็จจริงที่ว่า I/O ข้ามขอบเขต
ของ ถึง ตัวห่อหุ้มของ Norma เป็นโอเพนซอร์สและอยู่ภายใต้
norma/src/
เอกสารอ้างอิง#
radix/docs/design/frame-stream-types.md— ข้อกำหนดฉบับเต็มของ ช่องทาง, เฟรม, status, ส่ง, รับradix/docs/design/host-provider-gateway.md— สถาปัตยกรรมเราเตอร์ขนาดเล็ก สัญญาของผู้ให้บริการ และ compile manifestfaberlang/host-kernel-rs/— การใช้งานเราเตอร์เคอร์เนลfaberlang/host-native-rs/— การเชื่อมต่อและการลงทะเบียนแบบ nativefaberlang/host-providers-rs/— crate ผู้ให้บริการ (เฉพาะ, processus, consolum, tempus, aleator, http)examples/corpus/ad/— ไฟล์ตัวอย่าง ช่องทาง