mago_prelude/lib.rs
1//! A crate for building and loading Mago's "prelude".
2//!
3//! The prelude contains the pre-compiled `Database` and `CodebaseMetadata` for all
4//! of PHP's built-in symbols (functions, classes, constants, etc.). This is
5//! essential for providing accurate analysis, especially in environments like WASM
6//! where stubs cannot be loaded from the filesystem.
7//!
8//! ## Workflow
9//!
10//! This crate is split into two parts using a feature flag:
11//!
12//! 1. **At Compile Time (with the `build` feature):**
13//! - A `build.rs` script enables the `build` feature for this crate.
14//! - It calls `Prelude::build()` to perform the expensive, one-time analysis of all stub files.
15//! - It then calls `prelude.encode()` to serialize the result into a byte slice.
16//! - The bytes are written to a file (e.g., `prelude.bin`) in the `OUT_DIR`.
17//!
18//! 2. **At Runtime (without the `build` feature):**
19//! - The main application uses `include_bytes!` to embed the `prelude.bin` file.
20//! - It calls `Prelude::decode()` on the bytes to instantly reconstruct the prelude in memory.
21
22use bincode::config::standard;
23use serde::Deserialize;
24use serde::Serialize;
25
26use mago_codex::metadata::CodebaseMetadata;
27use mago_codex::reference::SymbolReferences;
28use mago_database::Database;
29
30use crate::error::PreludeError;
31
32pub mod error;
33
34#[cfg(feature = "build")]
35pub mod build;
36
37/// A container for the pre-compiled database and metadata of PHP's built-in symbols.
38///
39/// This struct holds all the necessary, fully-analyzed data for PHP's core library,
40/// allowing for instant startup without needing to parse and analyze stubs at runtime.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct Prelude {
43 /// The database of all built-in PHP files.
44 pub database: Database<'static>,
45 /// The fully populated and analyzed metadata for all symbols in the database.
46 pub metadata: CodebaseMetadata,
47 /// The collected symbol references from the analysis.
48 pub symbol_references: SymbolReferences,
49}
50
51impl Prelude {
52 /// Decodes a prelude from a byte slice.
53 ///
54 /// This is the primary runtime function, used to load a pre-compiled prelude
55 /// that was embedded in the binary. It is a very fast operation.
56 ///
57 /// # Errors
58 ///
59 /// Returns a [`PreludeError`] if deserialization fails due to corrupted or
60 /// incompatible binary data.
61 pub fn decode(bytes: &[u8]) -> Result<Self, PreludeError> {
62 let (prelude, _) = bincode::serde::decode_from_slice(bytes, standard())?;
63
64 Ok(prelude)
65 }
66
67 /// (Builder-only) Builds the prelude by parsing and analyzing all embedded PHP stub files.
68 ///
69 /// This is an expensive, one-time operation that should only be run at compile
70 /// time within a `build.rs` script. It is only available when the `build`
71 /// feature is enabled.
72 #[cfg(feature = "build")]
73 #[must_use]
74 pub fn build() -> Self {
75 build::build_prelude_internal()
76 }
77
78 /// (Builder-only) Encodes the prelude into a compact byte slice.
79 ///
80 /// The resulting `Vec<u8>` can be saved to a file for later loading.
81 /// This is only available when the `build` feature is enabled.
82 ///
83 /// # Errors
84 ///
85 /// Returns a [`PreludeError`] if serialization fails.
86 #[cfg(feature = "build")]
87 pub fn encode(&self) -> Result<Vec<u8>, PreludeError> {
88 Ok(bincode::serde::encode_to_vec(self, standard())?)
89 }
90}
91
92impl Default for Prelude {
93 fn default() -> Self {
94 let configuration =
95 mago_database::DatabaseConfiguration::new(std::path::Path::new("/"), vec![], vec![], vec![], vec![])
96 .into_static();
97
98 Self {
99 database: mago_database::Database::new(configuration),
100 metadata: CodebaseMetadata::default(),
101 symbol_references: SymbolReferences::default(),
102 }
103 }
104}