Class: MilkTea::StdCatalog

Inherits:
Object
  • Object
show all
Defined in:
lib/milk_tea/tooling/std_catalog.rb

Overview

Discovers the hand-written standard library modules shipped in std/, and resolves module names to source paths for tooling commands.

Generated modules (bindgen output under std/c/ and imported-binding wrappers such as raylib or zstd) are excluded from discovery but stay resolvable, so std show can still print them.

Defined Under Namespace

Classes: Entry

Constant Summary collapse

GENERATED_HEADER_PREFIX =
"# generated by mtc"
PLATFORM_SUFFIXES =
%w[linux windows wasm].freeze
EXCLUDED_DIRECTORIES =
%w[c].freeze
CATEGORY_ORDER =
[
  "Core & Patterns",
  "Collections",
  "Memory",
  "Text & Formatting",
  "Math & Simulation",
  "Data & Serialization",
  "Concurrency & Time",
  "Files & System",
  "Network",
  "Security",
  "AI & Behavior",
  "Game & Graphics",
].freeze
REGISTRY =

name => [category, description]. Must cover every hand-written module discovered under std/; a test enforces that coverage.

{
  "asset_pack" => ["Game & Graphics", "MTAP asset pack reader and writer for bundled runtime assets."],
  "async" => ["Concurrency & Time", "Async/await runtime facade over a pluggable event-loop backend."],
  "async.libuv_runtime" => ["Concurrency & Time", "libuv-backed async runtime implementation."],
  "async.mailbox" => ["Concurrency & Time", "Typed mailboxes for message passing between async tasks."],
  "async.runtime" => ["Concurrency & Time", "Async backend selection and event-loop plumbing shared by async code."],
  "base64" => ["Text & Formatting", "Base64 encode and decode."],
  "behavior_tree" => ["AI & Behavior", "Behavior trees with sequence, selector, decorator, and leaf nodes."],
  "binary" => ["Data & Serialization", "Binary reader/writer with explicit endianness and error reporting."],
  "binary_heap" => ["Collections", "Binary heap over a flat array with sift-up/sift-down operations."],
  "bitset" => ["Collections", "Fixed-capacity bit array with set, clear, test, and population count."],
  "blackboard" => ["AI & Behavior", "Typed key-value shared state for AI agents."],
  "box" => ["Core & Patterns", "Explicit single-value heap storage for owned boxed values."],
  "bytes" => ["Data & Serialization", "Byte buffer type with slicing, comparison, and stream I/O."],
  "cli" => ["Files & System", "Command-line parsing helpers for flags, options, and positionals."],
  "cmd" => ["Core & Patterns", "Command pattern with paired do/undo callbacks for undo/redo stacks."],
  "color" => ["Game & Graphics", "RGBA color conversion, blending, and named presets."],
  "cookie" => ["Data & Serialization", "HTTP cookie parsing and serialization."],
  "counter" => ["Collections", "Occurrence counter keyed by value, a counting multiset."],
  "crypto" => ["Security", "Digests, HMAC, and secure random via the platform crypto bindings."],
  "cstring" => ["Text & Formatting", "Null-terminated C string helpers backed by libc memory routines."],
  "ctype" => ["Text & Formatting", "Character classification: alnum, digit, space, and case tests."],
  "curl.runtime" => ["Network", "libcurl runtime glue for handle setup and error reporting."],
  "deque" => ["Collections", "Double-ended queue with amortized O(1) operations at both ends."],
  "encoding" => ["Text & Formatting", "UTF-8 validation, codepoint iteration, and encoding helpers."],
  "env" => ["Files & System", "Environment variable access returning Option values."],
  "errno" => ["Files & System", "errno code constants and error message lookup."],
  "fmt" => ["Text & Formatting", "Value formatting helpers for integers, floats, and fixed buffers."],
  "fs" => ["Files & System", "File and directory operations with platform-specific variants."],
  "fsm" => ["AI & Behavior", "Finite state machines with table-driven transitions and dispatch."],
  "goap" => ["AI & Behavior", "Goal-oriented action planning (GOAP) with forward search."],
  "graph" => ["Game & Graphics", "Weighted graph algorithms such as shortest paths and reachability."],
  "gzip" => ["Data & Serialization", "Gzip and zlib compression and decompression."],
  "hash" => ["Core & Patterns", "Canonical hash, equality, and ordering for common primitive types."],
  "htn" => ["AI & Behavior", "Hierarchical Task Network (HTN) planner."],
  "http" => ["Network", "HTTP client for requests, responses, and chunked bodies."],
  "http.server" => ["Network", "Small HTTP server with routing, static files, and JSON responses."],
  "input" => ["Game & Graphics", "Input action mapping that decouples logical actions from physical devices."],
  "intern" => ["Text & Formatting", "String interning table producing unique identifier handles."],
  "iter" => ["Core & Patterns", "Composable lazy iteration adaptors over sequences."],
  "jobs" => ["Concurrency & Time", "Job scheduler for fan-out parallel work with completion tracking."],
  "json" => ["Data & Serialization", "JSON parsing and serialization over cjson with arena-backed values."],
  "libc" => ["Files & System", "Curated libc facade for memory, string, process, and math functions."],
  "linear_algebra" => ["Math & Simulation", "Vectors and matrices for 2D/3D graphics and physics."],
  "linked_map" => ["Collections", "Hash map with a doubly-linked order list for O(1) reordering."],
  "linked_map_view" => ["Collections", "Read-only snapshot views over linked_map instances."],
  "linked_set" => ["Collections", "Insertion-ordered hash set backed by a linked list."],
  "log" => ["Files & System", "Leveled logging with configurable output sinks."],
  "lru_cache" => ["Collections", "Least-recently-used cache with bounded capacity."],
  "map" => ["Collections", "Chained hash map with pluggable hashing for generic keys and values."],
  "math" => ["Math & Simulation", "Mathematical constants and functions beyond the language builtins."],
  "mem.arena" => ["Memory", "Region allocator: bump allocation with O(1) mark/reset."],
  "mem.endian" => ["Memory", "Byte-swap and endian conversion helpers."],
  "mem.heap" => ["Memory", "General-purpose heap allocator wrapper with alignment control."],
  "mem.pool" => ["Memory", "Fixed-slot pool allocator for uniform-size objects."],
  "mem.ptr" => ["Memory", "Safe pointer load/store wrappers around raw memory access."],
  "mem.stack" => ["Memory", "Stack allocator with mark/release layered on the arena."],
  "mem.tracking" => ["Memory", "Allocation tracker for leak detection and usage diagnostics."],
  "multiset" => ["Collections", "Hash multiset that counts duplicate values."],
  "net" => ["Network", "UDP and TCP sockets, address resolution, and packet I/O."],
  "net.channel" => ["Network", "Multiplexed message channels over a single connection."],
  "net.clock" => ["Network", "Synchronized network clock with ping and offset estimation."],
  "net.discovery" => ["Network", "LAN service discovery via UDP broadcast."],
  "net.lobby" => ["Network", "Lobby listing and joining built on discovery."],
  "net.manager" => ["Network", "Connection and session manager for multiplayer topologies."],
  "net.mux" => ["Network", "Stream multiplexer with reliable and unordered delivery flags."],
  "net.nat" => ["Network", "NAT type detection and address binding via STUN."],
  "net.packet" => ["Network", "Framed packet reading and writing over byte streams."],
  "net.punch" => ["Network", "UDP hole punching for peer-to-peer connections."],
  "net.rpc" => ["Network", "Request/response RPC framing over net channels."],
  "net.session" => ["Network", "Client session state machine with heartbeats and timeouts."],
  "net.stun" => ["Network", "STUN client for public address and port discovery."],
  "net.sync" => ["Network", "State synchronization primitives for replicated values."],
  "net.turn" => ["Network", "TURN relay client for NAT-restricted peers."],
  "noise" => ["Math & Simulation", "Coherent Perlin noise and fractal variants."],
  "oauth2" => ["Data & Serialization", "OAuth2 token requests and refresh flows."],
  "option" => ["Core & Patterns", "Option[T] optional values, some(value) or none, with combinators."],
  "ordered_map" => ["Collections", "Hash map that preserves insertion order."],
  "ordered_set" => ["Collections", "Hash set that preserves insertion order."],
  "parse" => ["Text & Formatting", "Numeric string parsing for integers and floats."],
  "path" => ["Files & System", "Path join, split, and normalization utilities."],
  "pcre2.runtime" => ["Text & Formatting", "Compiled regex matching runtime over the pcre2 bindings."],
  "pool" => ["Collections", "Fixed-capacity reusable object storage."],
  "priority_queue" => ["Collections", "Priority queue backed by a binary heap."],
  "process" => ["Files & System", "Child process spawning with pipes and exit status."],
  "queue" => ["Collections", "First-in first-out queue."],
  "random" => ["Math & Simulation", "PCG pseudo-random number generation with seeding and ranges."],
  "raylib.debug_console" => ["Game & Graphics", "In-game debug console overlay with command history."],
  "raylib.easing" => ["Game & Graphics", "Easing curves for animation interpolation."],
  "raylib.packed_assets" => ["Game & Graphics", "Load images, textures, and audio from assets.mtpack packs."],
  "raylib.runtime" => ["Game & Graphics", "raylib app lifecycle helpers: window loop, asset directory, fatal errors."],
  "raylib.tracy_gpu" => ["Game & Graphics", "Tracy profiler GPU zone calibration for raylib."],
  "result" => ["Core & Patterns", "Result[T, E] success/failure type for recoverable errors."],
  "ring_buffer" => ["Collections", "Fixed-capacity circular buffer with overwrite behavior."],
  "sdl3.runtime" => ["Game & Graphics", "SDL3 app lifecycle helpers and main-loop wrappers."],
  "serialize" => ["Data & Serialization", "Struct field serialization helpers layered on std.binary."],
  "set" => ["Collections", "Hash set of unique values."],
  "signal" => ["Concurrency & Time", "Fixed-capacity observer and publish-subscribe signals."],
  "simd" => ["Math & Simulation", "SIMD load, store, and reduction helpers."],
  "sparse_set" => ["Collections", "Sparse set with dense iteration for integer-keyed data."],
  "spatial" => ["Math & Simulation", "Uniform spatial hash grid for broad-phase queries."],
  "stack" => ["Collections", "Last-in first-out stack."],
  "steering" => ["AI & Behavior", "Craig Reynolds steering behaviors for autonomous motion."],
  "stdio" => ["Files & System", "Stdin, stdout, and stderr FILE wrappers and console I/O."],
  "str" => ["Text & Formatting", "Borrowed string slice helpers: length, compare, search, split."],
  "string" => ["Text & Formatting", "Heap-owned growable string type with builder operations."],
  "sync" => ["Concurrency & Time", "Mutex, condition variable, and once primitives over libuv."],
  "tar" => ["Data & Serialization", "TAR archive reading and writing with 512-byte blocks."],
  "terminal" => ["Files & System", "Terminal size, color, and raw-mode helpers."],
  "thread" => ["Concurrency & Time", "Threads via libuv with join and handle management."],
  "time" => ["Concurrency & Time", "Wall-clock timestamps and monotonic time helpers."],
  "timer" => ["Concurrency & Time", "Countdown and repeating timers."],
  "tls" => ["Security", "TLS client and server streams over libuv handles."],
  "toml" => ["Data & Serialization", "TOML parser for configuration files."],
  "tween" => ["Game & Graphics", "Tweening and easing for smooth value interpolation."],
  "uri" => ["Data & Serialization", "URI parsing and construction, including file and web schemes."],
  "url" => ["Data & Serialization", "URL parsing: scheme, host, path, query, and percent-encoding."],
  "utility" => ["AI & Behavior", "Utility AI with score-based action selection."],
  "vec" => ["Collections", "Growable contiguous array Vec[T], the default dynamic sequence."],
}.freeze

Class Method Summary collapse

Class Method Details

.add_module(by_name, name, path) ⇒ Object



201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/milk_tea/tooling/std_catalog.rb', line 201

def add_module(by_name, name, path)
  return if generated?(path)

  category, description = REGISTRY.fetch(name, [nil, nil])
  description ||= doc_comment_summary(path)
  entry = by_name[name]
  unless entry
    by_name[name] = Entry.new(name:, description:, category:, path:)
    return
  end

  entry.path = path if prefer_path?(path, entry.path)
end

.discoverObject



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/milk_tea/tooling/std_catalog.rb', line 183

def discover
  root = std_root
  by_name = {}

  module_files(root).each do |path|
    add_module(by_name, logical_name(path), path)
  end

  namespace_directories(root).each do |directory|
    namespace = File.basename(directory)
    module_files(directory).each do |path|
      add_module(by_name, "#{namespace}.#{logical_name(path)}", path)
    end
  end

  by_name.values.sort_by(&:name)
end

.doc_comment_summary(path) ⇒ Object



262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/milk_tea/tooling/std_catalog.rb', line 262

def doc_comment_summary(path)
  File.foreach(path) do |line|
    stripped = line.strip
    next if stripped.empty?

    return stripped.sub(/\A##\s?/, "").rstrip if stripped.start_with?("##")

    break
  end
  nil
rescue Errno::ENOENT
  nil
end

.entriesObject



160
161
162
# File 'lib/milk_tea/tooling/std_catalog.rb', line 160

def entries
  discover
end

.generated?(path) ⇒ Boolean

Returns:

  • (Boolean)


256
257
258
259
260
# File 'lib/milk_tea/tooling/std_catalog.rb', line 256

def generated?(path)
  File.open(path, "r") { |file| file.readline.start_with?(GENERATED_HEADER_PREFIX) }
rescue EOFError, Errno::ENOENT
  false
end

.logical_name(path) ⇒ Object



240
241
242
243
244
# File 'lib/milk_tea/tooling/std_catalog.rb', line 240

def logical_name(path)
  stem = File.basename(path, ".mt")
  platform = platform_of(path)
  platform ? stem.delete_suffix(".#{platform}") : stem
end

.module_files(directory) ⇒ Object



229
230
231
# File 'lib/milk_tea/tooling/std_catalog.rb', line 229

def module_files(directory)
  Dir.glob(File.join(directory, "*.mt")).sort
end

.namespace_directories(root) ⇒ Object



233
234
235
236
237
238
# File 'lib/milk_tea/tooling/std_catalog.rb', line 233

def namespace_directories(root)
  Dir.children(root).map { |child| File.join(root, child) }
     .select { |path| File.directory?(path) }
     .reject { |path| EXCLUDED_DIRECTORIES.include?(File.basename(path)) }
     .sort
end

.path_rank(path) ⇒ Object



224
225
226
227
# File 'lib/milk_tea/tooling/std_catalog.rb', line 224

def path_rank(path)
  host = MilkTea.host_platform.to_s
  [platform_variant?(path) ? 1 : 0, platform_of(path) == host ? 0 : 1]
end

.platform_of(path) ⇒ Object



250
251
252
253
254
# File 'lib/milk_tea/tooling/std_catalog.rb', line 250

def platform_of(path)
  stem = File.basename(path, ".mt")
  suffix = stem[/\.([^.]+)\z/, 1]
  suffix && PLATFORM_SUFFIXES.include?(suffix) ? suffix : nil
end

.platform_variant?(path) ⇒ Boolean

Returns:

  • (Boolean)


246
247
248
# File 'lib/milk_tea/tooling/std_catalog.rb', line 246

def platform_variant?(path)
  PLATFORM_SUFFIXES.include?(platform_of(path))
end

.prefer_path?(candidate, current) ⇒ Boolean

A shared file beats any variant; among variants the host platform wins, then the first alphabetically.

Returns:

  • (Boolean)


217
218
219
220
221
222
# File 'lib/milk_tea/tooling/std_catalog.rb', line 217

def prefer_path?(candidate, current)
  candidate_rank = path_rank(candidate)
  current_rank = path_rank(current)
  order = candidate_rank <=> current_rank
  order.negative? || (order.zero? && candidate < current)
end

.resolve(name) ⇒ Object

Resolves a module name ("mem.arena", "mem/arena", "c.cjson", "fs") to a source path. Prefers the active platform variant, matching the compiler's import resolution rule. Returns nil when unresolvable.



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/milk_tea/tooling/std_catalog.rb', line 167

def resolve(name)
  clean = name.to_s.strip
  return nil if clean.empty? || clean.include?("..")

  relative = clean.tr(".", "/").delete_suffix(".mt")
  root = std_root

  variant = File.join(root, "#{relative}.#{MilkTea.host_platform}.mt")
  return variant if File.file?(variant)

  shared = File.join(root, "#{relative}.mt")
  return shared if File.file?(shared)

  nil
end

.std_rootObject



156
157
158
# File 'lib/milk_tea/tooling/std_catalog.rb', line 156

def std_root
  File.join(MilkTea.root.to_s, "std")
end