///|
/// Task Scheduler Types
/// Browser Event Loop / Task Queue に相当する型定義
// =============================================================================
// Task Identifier
// =============================================================================
///|
/// Unique task identifier
pub(all) struct TaskId(Int) derive(Eq, Hash, Debug)
///|
/// ID generator (mutable state in struct)
priv struct TaskIdGenerator {
mut next_id : Int
}
///|
let task_id_gen : TaskIdGenerator = { next_id: 0 }
///|
fn TaskId::next() -> TaskId {
let id = task_id_gen.next_id
task_id_gen.next_id += 1
TaskId(id)
}
///|
/// Reset task ID counter (for testing)
pub fn reset_task_id_counter() -> Unit {
task_id_gen.next_id = 0
}
// =============================================================================
// Task Source (Browser Task Source に相当)
// =============================================================================
///|
/// タスクの発生源
pub(all) enum TaskSource {
/// DOM操作(パース、ツリー構築)
DOM
/// スタイル計算
Styling
/// レイアウト計算
Layout
/// リソースフェッチ(外部委譲)
Networking
/// スクリプト実行(外部委譲)
Scripting
/// 画像デコード(外部委譲)
ImageDecode
} derive(Eq, Hash, Debug)
// =============================================================================
// Task Constraint (実行制約)
// =============================================================================
///|
/// タスクの実行制約
pub(all) enum TaskConstraint {
/// メインスレッド必須(DOM操作など)
MainThreadOnly
/// 並列実行可能(画像デコード、一部のスタイル計算)
Parallel
/// 他のタスクソースをブロック(parser-blocking script)
Blocking(Array[TaskSource])
} derive(Debug)
///|
/// Check if a task can run in parallel
pub fn TaskConstraint::is_parallel(self : TaskConstraint) -> Bool {
match self {
Parallel => true
_ => false
}
}
///|
/// Check if a task blocks a specific source
pub fn TaskConstraint::blocks(
self : TaskConstraint,
source : TaskSource,
) -> Bool {
match self {
Blocking(sources) => sources.contains(source)
_ => false
}
}
// =============================================================================
// Resource Type
// =============================================================================
///|
/// リソースの種類
pub(all) enum ResourceType {
/// HTML ドキュメント
Document
/// スタイルシート
Stylesheet
/// JavaScript
Script
/// 画像
Image
/// フォント
Font
/// その他
Other
} derive(Eq, Debug)
// =============================================================================
// Task State
// =============================================================================
///|
/// タスクの状態
pub(all) enum TaskState {
/// 依存タスク待ち
Pending
/// 実行可能(依存解決済み)
Ready
/// 実行中(外部で実行中)
Running
/// 完了
Completed
/// キャンセル
Cancelled
/// 失敗
Failed(String)
} derive(Debug)
///|
pub fn TaskState::is_terminal(self : TaskState) -> Bool {
match self {
Completed | Cancelled | Failed(_) => true
_ => false
}
}
///|
pub fn TaskState::is_runnable(self : TaskState) -> Bool {
match self {
Ready => true
_ => false
}
}
// =============================================================================
// Task Action (実行内容)
// =============================================================================
///|
/// タスクの実行内容
pub(all) enum TaskAction {
// -------------------------------------------------------------------------
// 内部実行可能(同期的に実行可能)
// -------------------------------------------------------------------------
/// HTMLチャンクをパース
ParseHTMLChunk(html~ : String)
/// CSSをパース
ParseCSS(source~ : String)
/// スタイル計算(指定ノードまたは全体)
ComputeStyle(node_ids~ : Array[String])
/// レイアウト計算
ComputeLayout
// -------------------------------------------------------------------------
// 外部委譲(非同期実行が必要)
// -------------------------------------------------------------------------
/// リソースフェッチ
FetchResource(url~ : String, resource_type~ : ResourceType)
/// 画像デコード
DecodeImage(resource_id~ : Int)
/// スクリプト実行
ExecuteScript(source~ : String)
} derive(Debug)
///|
pub impl Show for TaskId with fn output(self, logger) {
logger.write_string("TaskId(\{self.0})")
}
///|
pub impl Show for TaskSource with fn output(self, logger) {
let name = match self {
DOM => "DOM"
Styling => "Styling"
Layout => "Layout"
Networking => "Networking"
Scripting => "Scripting"
ImageDecode => "ImageDecode"
}
logger.write_string(name)
}
///|
pub impl Show for TaskConstraint with fn output(self, logger) {
match self {
MainThreadOnly => logger.write_string("MainThreadOnly")
Parallel => logger.write_string("Parallel")
Blocking(sources) => logger.write_string("Blocking(\{to_repr(sources)})")
}
}
///|
pub impl Show for ResourceType with fn output(self, logger) {
let name = match self {
Document => "Document"
Stylesheet => "Stylesheet"
Script => "Script"
Image => "Image"
Font => "Font"
Other => "Other"
}
logger.write_string(name)
}
///|
pub impl Show for TaskState with fn output(self, logger) {
match self {
Pending => logger.write_string("Pending")
Ready => logger.write_string("Ready")
Running => logger.write_string("Running")
Completed => logger.write_string("Completed")
Cancelled => logger.write_string("Cancelled")
Failed(error) => {
logger.write_string("Failed(")
logger.write_string("\"")
logger.write_string(error)
logger.write_string("\"")
logger.write_string(")")
}
}
}
///|
pub impl Show for TaskAction with fn output(self, logger) {
match self {
ParseHTMLChunk(html~) => {
logger.write_string("ParseHTMLChunk(html=")
logger.write_string("\"")
logger.write_string(html)
logger.write_string("\"")
logger.write_string(")")
}
ParseCSS(source~) => {
logger.write_string("ParseCSS(source=")
logger.write_string("\"")
logger.write_string(source)
logger.write_string("\"")
logger.write_string(")")
}
ComputeStyle(node_ids~) =>
logger.write_string("ComputeStyle(node_ids=\{to_repr(node_ids)})")
ComputeLayout => logger.write_string("ComputeLayout")
FetchResource(url~, resource_type~) => {
logger.write_string("FetchResource(url=")
logger.write_string("\"")
logger.write_string(url)
logger.write_string("\"")
logger.write_string(", resource_type=\{resource_type})")
}
DecodeImage(resource_id~) =>
logger.write_string("DecodeImage(resource_id=\{resource_id})")
ExecuteScript(source~) => {
logger.write_string("ExecuteScript(source=")
logger.write_string("\"")
logger.write_string(source)
logger.write_string("\"")
logger.write_string(")")
}
}
}
///|
pub impl Show for TaskResult with fn output(self, logger) {
match self {
Success(new_tasks~) =>
logger.write_string("Success(new_tasks=\{to_repr(new_tasks)})")
Failure(error~) => {
logger.write_string("Failure(error=")
logger.write_string("\"")
logger.write_string(error)
logger.write_string("\"")
logger.write_string(")")
}
Cancelled => logger.write_string("Cancelled")
}
}
///|
/// Check if action can be executed internally (synchronously)
pub fn TaskAction::is_internal(self : TaskAction) -> Bool {
match self {
ParseHTMLChunk(_) | ParseCSS(_) | ComputeStyle(_) | ComputeLayout => true
FetchResource(_) | DecodeImage(_) | ExecuteScript(_) => false
}
}
///|
/// Get the task source for this action
pub fn TaskAction::source(self : TaskAction) -> TaskSource {
match self {
ParseHTMLChunk(_) => DOM
ParseCSS(_) => Styling
ComputeStyle(_) => Styling
ComputeLayout => Layout
FetchResource(_) => Networking
DecodeImage(_) => ImageDecode
ExecuteScript(_) => Scripting
}
}
// =============================================================================
// Task Result
// =============================================================================
///|
/// タスクの実行結果
pub(all) enum TaskResult {
/// 成功(追加タスクを生成する場合がある)
Success(new_tasks~ : Array[TaskAction])
/// 失敗
Failure(error~ : String)
/// キャンセル
Cancelled
} derive(Debug)
// =============================================================================
// Task
// =============================================================================
///|
/// タスク本体
pub(all) struct Task {
/// 一意な識別子
id : TaskId
/// タスクの種類
source : TaskSource
/// 実行制約
constraint : TaskConstraint
/// 依存するタスク(これらが完了するまで実行不可)
dependencies : Array[TaskId]
/// 実行内容
action : TaskAction
/// 現在の状態
mut state : TaskState
/// 優先度(高いほど優先)
priority : Int
}
///|
pub fn Task::new(
action : TaskAction,
constraint : TaskConstraint,
dependencies? : Array[TaskId] = [],
priority? : Int = 0,
) -> Task {
{
id: TaskId::next(),
source: action.source(),
constraint,
dependencies,
action,
state: if dependencies.is_empty() {
Ready
} else {
Pending
},
priority,
}
}
///|
pub fn Task::is_ready(self : Task) -> Bool {
self.state.is_runnable()
}
///|
pub fn Task::is_parallel(self : Task) -> Bool {
self.constraint.is_parallel()
}
///|
pub fn Task::is_completed(self : Task) -> Bool {
match self.state {
Completed => true
_ => false
}
}
///|
pub fn Task::is_terminal(self : Task) -> Bool {
self.state.is_terminal()
}
///|
pub fn Task::mark_running(self : Task) -> Unit {
self.state = Running
}
///|
pub fn Task::mark_completed(self : Task) -> Unit {
self.state = Completed
}
///|
pub fn Task::mark_failed(self : Task, error : String) -> Unit {
self.state = Failed(error)
}
///|
pub fn Task::mark_cancelled(self : Task) -> Unit {
self.state = Cancelled
}