odem_rs_meta/lib.rs
1//! This crate provides procedural macros for meta-programming purposes to be
2//! used in concert with the ODEM-rs library.
3//!
4//! It includes four main macros:
5//!
6//! - `until`: Parses a condition into a `ControlExpr` that can be awaited.
7//! - `derive_config`: Derives the `Config` trait for a structure, supporting
8//! customizations through attributes.
9//! - `derive_publisher`: Generates the `Publisher` trait by subscribing to
10//! marked attributes.
11//! - `sim_main`: Wraps a user-defined `async fn` with optional arguments and
12//! return values into a synchronous wrapper-function that initializes and
13//! runs a simulation, returning its results.
14//!
15//! For more details, refer to the documentation of each macro.
16#![doc(
17 html_logo_url = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxjaXJjbGUgY3k9IjE5Ny41IiBjeD0iMjAwLjUiIHN0cm9rZT0iIzAwMCIgZmlsbD0iI2ZmZiIgcj0iMTUyLjUiLz48cGF0aCBkPSJNMTkxLjI0NyAzLjYyNmMtMTAuMDIuNjEtMTAuMDg1LjcxLTEyLjgzOSAxOS40NzYtMS41NDEgMTAuNDk2LTIuMTE2IDExLjU2Ni02LjczMiAxMi41MjMtMTIuNzIyIDIuNjM3LTIwLjg2MyA0Ljg0OS0yOS45ODcgOC4xNDgtMTEuNDUyIDQuMTQtMTkuOTcyIDguMjA5LTMwLjU3IDE0LjU5OS03LjIxMyA0LjM0OS01LjgzOCA0Ljc5Ny0xOC45MDgtNi4xNTgtOS4wODQtNy42MTMtMTAuMDA3LTguMDc3LTEzLjkxNi02Ljk5Mi00LjMyNSAxLjIwMS0yMi42NzUgMTguNDU5LTI1LjAwMyAyMy41MTUtMS43MjUgMy43NDQtMS40MTcgNC40MjggNy4xNDEgMTUuODYzIDguMjQzIDExLjAxNSA4LjEwMSAxMC42MjMgNS4yMzkgMTQuNDEtMTQuMzY2IDE5LjAwNy0yNS4zNjYgNDMuNjAzLTMwLjA2NiA2Ny4yMjUtMS42MDggOC4wODQuNjI1IDYuOTI2LTIxLjEwOCAxMC45NDdDMy44MTIgMTc5LjE1OCAzLjgxNiAxNzkuMTUyIDMuODMzIDE5OGMuMDIgMjAuNDcxLTIuMDg1IDE4LjQ4MyAyMy45NjcgMjIuNjQ0IDYuNDggMS4wMzUgNi40NDMuOTkyIDcuODI1IDkuMTIgMy45OTMgMjMuNDcgMTQuMTU0IDQ4LjEwMiAyNy40ODMgNjYuNjIyIDQuMDk1IDUuNjkgNC43MzcgNy4xNzQgMy44NTMgOC45MDUtLjgyNCAxLjYxMy01LjY1NSA4LjY2Ni05Ljg0NCAxNC4zNzMtNS4xMTkgNi45NzQtNS43NjYgOS41OTItMy4yNjUgMTMuMjIgMS43NjYgMi41NjMgMTMuMDg4IDEzLjc3NiAxNy4zODQgMTcuMjE3IDkuMTcxIDcuMzQ2IDkuNTAxIDcuMjk3IDIyLjU2NC0zLjM0MiAxMS43NDQtOS41NjQgMTAuMzExLTkuMTk4IDE3Ljk4OC00LjU5MiAxNy4wNzQgMTAuMjQ0IDM1LjYzNyAxNy4yOTIgNTcuNTU0IDIxLjg1MiA3LjAyNSAxLjQ2MSA3LjAyMSAxLjQ1MyA5LjY1OSAxNi4wMzEgMi4zMjMgMTIuODM0IDMuMDI0IDE0LjQzNyA2Ljc5OSAxNS41NDIgMi4yMzUuNjU0IDE5Ljg0Ny45OTggMjQuODc0LjQ4NSA3LjgwNS0uNzk2IDcuODU4LS44NzIgMTAuNzMtMTUuNDQyIDIuOTc4LTE1LjExIDIuOTYzLTE1LjA4NyAxMC43MTYtMTYuNjEyIDE5LjMwNC0zLjc5OSAzOC4xNDctMTAuODMzIDU2Ljg3NS0yMS4yMjkgMy45NTgtMi4xOTcgNy41MDEtMy45OTQgNy44NzUtMy45OTQgMS4wMDIgMCA0LjY0OSAyLjcxNCAxMi4wOTEgOSAxMi4xMzggMTAuMjUzIDEzLjU0NiAxMC4wMjEgMjguNjAyLTQuNzIzIDEyLjQ4My0xMi4yMjUgMTMuMDA4LTE0LjE3OSA2LjI1Mi0yMy4yNzctMTEuODQyLTE1Ljk0Ny0xMS42MzMtMTUuNDY0LTguNTk0LTE5Ljg3IDE3LjQwMy0yNS4yMzMgMjUuNjY1LTQ0Ljk3MSAzMC41NTYtNzIuOTkzLjk3MS01LjU2Mi40MzgtNS4zMTUgMTcuMjIzLTcuOTgzIDkuNzk3LTEuNTU3IDExLjMyMi0yLjA3IDEyLjQwOC00LjE3IDIuMTMyLTQuMTIzIDIuMzctMjguMTEzLjMyOS0zMy4yMjMtLjk4NS0yLjQ2Ni0yLjE1Ny0yLjk4OC0xMC4xOTQtNC41MzktMjEuMDU3LTQuMDY1LTE4LjU5Ni0yLjU2OS0yMC43NTEtMTIuNjIyLTQuNzIzLTIyLjAyNy0xMy43NDEtNDIuNTUzLTI2Ljg4OC02MS4yLTYuMDA3LTguNTE5LTYuMDgxLTcuNjA5IDEuMzg0LTE3LjA1NyA4LjczMy0xMS4wNTQgOS42MzMtMTIuNzIyIDguNzEyLTE2LjE0Mi0xLjMyOS00LjkzOC0yMC44Mi0yMy40ODgtMjYuMDY3LTI0LjgwOS0zLjYzOC0uOTE2LTQuNDY4LS40MjgtMTUuNDc4IDkuMTEzLTkuODgyIDguNTYyLTkuMjA5IDguMzUzLTE1LjAxNSA0LjY2Ni0xNS44NDEtMTAuMDYtMzcuMDE4LTE4LjMyMy01OC43NDktMjIuOTI1LTguNzQ1LTEuODUxLTcuNjU2LjE4OS0xMi4wNDgtMjIuNTYxLTEuNDEyLTcuMzE1LTIuNDg2LTguOC02Ljg0OC05LjQ2My0zLjcxNy0uNTY1LTE2LjE3Ni0uNzg0LTIyLjU0OC0uMzk2TTIwOS40IDU1LjIxMWM5Ni4xMTQgNi4zODEgMTU5LjYzMSA5OS42NDIgMTI5LjY2NyAxOTAuMzg5LTMzLjk1NCAxMDIuODMzLTE2NC42NzcgMTMzLjQ1LTI0MS42OTIgNTYuNjA3LTQyLjMzNS00Mi4yNDEtNTQuNTAzLTk5LjE0Mi0zMy4yMzYtMTU1LjQyOSAyMS4yMy01Ni4xODYgODMuODI3LTk1LjY0NiAxNDUuMjYxLTkxLjU2N20tMjIuNiAxMC41ODdjLTI0LjcyNiAyLjI5My00NS4zMzEgMTAuODExLTU1LjI4MSAyMi44NTFsLTEuNjEzIDEuOTUxIDcwLjE0Ny4yIDcwLjI5MS4xMjNjLjg5Ni0uNDgtNy4xOTctNy44MjMtMTIuNTQ0LTExLjM3OS0xNi40NDctMTAuOTQtNDMuOTE3LTE2LjI1OC03MS0xMy43NDZtOTUuNjMxIDI4LjU2OGMzLjc5NCAxMS43OTYgNC4wOTMgMjYuNTc2Ljc1OCAzNy4zNzQtMS4wNTQgMy40MTUtMS43MzUgMy4yNjIgNi4yMDggMS4zOWw2Ljc5OC0xLjYwMiAxLjEzNCAxLjMzNmMzLjIgMy43NyAxMS4wNzEgMTcuNDkzIDExLjA3MSAxOS4zMDIgMCAuNzUyLTQuNDUgNC44NDgtMTQuNiAxMy40NDFsLTExLjA3MiA5LjUxM2MtMS42NTMgMS41NTktMi40ODkgMS41MDQtMi45MDEtLjE4OC0uNTI4LTIuMTcyLTUuMzgxLTExLjU2Mi03Ljk5NC0xNS40NjctMy4xMzUtNC42ODUtMy4wNDktMy41MDItLjY1Ni05LjA2NSA1LjMzMS0xMi4zOSA3LjU4NC0zMS44NjYgNS4zMjMtNDZsLS43MzYtNC42LTkuNTE1LjA2NmMtMTAuNDU2LjA3Mi0xMC4yOTIuMDQ0LTkuMTExIDEuNTQ2IDMuOTIzIDQuOTg4IDUuNTYzIDIwLjA2MyAzLjM0MSAzMC43MDQtMy43MzQgMTcuODcxLTEyLjk3MSAzMS41MjEtMzIuMTM2IDQ3LjQ4OC0xMy41MTIgMTEuMjU2LTE1LjkgMTQuNTU2LTE1LjkzMyAyMi4wMTItLjAzMSA3LjAzNSAyLjMxIDEwLjUzNiAxMy4xOSAxOS43MjkgMTUuMzEgMTIuOTM0IDIzLjEwOCAyMS45NDQgMjguODYxIDMzLjM0MiA3LjY1NiAxNS4xNzEgOS4yMDkgMzMuOTUxIDMuNzMzIDQ1LjE2OS0uNzY3IDEuNTctMS4zOTQgMi45NjUtMS4zOTQgMy4xczQuMTQ0LjI0NCA5LjIxLjI0NGg5LjIxbC4zNTUtLjkzNWMxLjI0MS0zLjI2MyAyLjIzMi0xOC4wMjQgMS42NTItMjQuNjA1LS45OTQtMTEuMjk0LTIuOTUtMTguODYzLTcuMzkxLTI4LjYwOGwtMS40MS0zLjA5NSAyLjQ0Ny0zLjYzNGMyLjg3My00LjI2NiA2LjUwNy0xMS40NDcgOC4zNjItMTYuNTIzLjcyMy0xLjk4IDEuNDQ2LTMuNzU2IDEuNjA2LTMuOTQ2czIuMTUxIDEuMzQ4IDQuNDI1IDMuNDE3YTQ0NyA0NDcgMCAwIDAgOC41MzQgNy41MjdjNy4wOTMgNi4wNjggMTIuNjM1IDExLjI3MyAxMy42NzIgMTIuODM5bC45NjUgMS40NTgtMi41NDYgNS4zNTNjLTIuNzczIDUuODI2LTYuNTU3IDEyLjMxLTguMjAyIDE0LjA1Mi0xLjMzMyAxLjQxMi0xLjUyOSAxLjQwMS05LjA3Ny0uNDk3LTcuMzg2LTEuODU3LTYuODI4LTEuOTU2LTUuOCAxLjAzMSAzLjM1MyA5Ljc0NCAzLjY5OSAyNy4xMTguNzU5IDM4LjA5NC0xLjMwNSA0Ljg3NS0uOTk0IDQuNzE1IDkuMTY1LTQuNyA2Mi45OTQtNTguMzc4IDU5LjMwMy0xNTUuNTQ1LTcuODc3LTIwNy4zNTktMy43OC0yLjkxNS0zLjc4Mi0yLjkxNC0yLjQyOCAxLjI5N00xMTUuNCA5My4wNDRjLTMuMTQ1IDIuMzU1LTguMTQ4IDYuOS0xMy42IDEyLjM1Ni01NS44MTEgNTUuODUtNTAuNSAxNTAuODAyIDExLjEyMyAxOTguODMxIDQuNTE2IDMuNTIgNC42MDMgMy41MjEgMy41MzUuMDY0LTMuMjg0LTEwLjYzNS0zLjIwNS0yNS42MjUuMTk0LTM2LjM4MiAxLjI0LTMuOTI2IDEuOTA2LTMuNzE3LTUuNzQzLTEuNzk5LTcuMzk3IDEuODU1LTYuODIyIDEuOTU4LTkuNDk1LTEuNzA3LTEuNzM2LTIuMzgtNy4wNTItMTIuMDAyLTguMjEtMTQuODYyLTEuNDkyLTMuNjgyLTIuNjM3LTIuMzMgMTYuMzMtMTkuMjg2bDYuMzY0LTUuNzI1YzMuMjE3LTIuOTExIDQuMTAyLTMuMjgyIDQuMTAyLTEuNzIxIDAgMi4yNTEgNC41NTEgMTEuNTUzIDguOTg1IDE4LjM2M2wyLjYyNSA0LjAzMy0xLjk5NiA0LjA5NWMtNi43MzUgMTMuODE5LTkuNDggMzQuOTQ2LTYuNTExIDUwLjA5NmwuNzA2IDMuNiA5LjE4Ny4xMDhjMTEuMDMuMTI5IDEwLjUzMS4yNTggOC44MjgtMi4yNzMtNS4xMTctNy42MDMtNS41OTktMjIuNjc4LTEuMTUyLTM2LjAzIDUuMTY3LTE1LjUxNSAxNS4zNjQtMjguOTI4IDMzLjQxLTQzLjk1MSA5LjAxNy03LjUwNiAxMS4zNjctMTAuNTM2IDEyLjYwOC0xNi4yNTQgMS43MjYtNy45NTYtLjk2OC0xMi44OTQtMTEuODItMjEuNjY1LTI0Ljk5NS0yMC4yMDItMzUuMTc3LTM1Ljk3Mi0zNi45NTUtNTcuMjM2LS44NjQtMTAuMzM4LjI2Ni0xNy41MjQgMy42NTgtMjMuMjYuOTEyLTEuNTQzIDEuMTQyLTIuMjQ0LjgwMi0yLjQ1NC0uNzI0LS40NDgtMTguMTMuMDQ2LTE4LjQzNC41MjItLjU1Ni44NzMtMS41MjkgOC43ODgtMS43ODEgMTQuNDkzLS41OTQgMTMuMzkyIDIuMDIxIDI3LjQ3IDcuMDIyIDM3LjgxMy44NzggMS44MTQgMS40ODIgMy40OTkgMS4zNDQgMy43NDNzLTEuMTkgMS44ODQtMi4zMzYgMy42NDRjLTIuODk1IDQuNDQ1LTYuMTUgMTAuOTktNy45MjcgMTUuOTMzLS4yOTguODMxLS45NjcuMzg1LTUuNjkxLTMuNzg4LTEuMzM1LTEuMTgtNC41NjgtMy45NDUtNy4xODYtNi4xNDUtMTAuNzcyLTkuMDU1LTE0Ljk4Ni0xMy4xMDMtMTQuOTg2LTE0LjM5NCAwLTIuMTg5IDcuMzY5LTE1LjEzMiAxMC41MzYtMTguNTA2IDEuNTI2LTEuNjI1IDIuMTY5LTEuNjM0IDguNjYxLS4xMjQgNS44NTcgMS4zNjIgNS40MDIgMS41MDcgNC42MzEtMS40Ny0zLjIzMy0xMi40NzUtMi44ODgtMjUuNTA2Ljk4My0zNy4xMzkgMS4xNTMtMy40NjQuOTc4LTMuNjExLTEuODExLTEuNTIzbTM4LjMyOSA3Ljc4NGMtNC45MTkgMi40MzUtOC45MTggMTAuMTcxLTYuNTUgMTIuNjcybC44NTIuOWgxMDMuNTUxbC42ODItMS4wNDJjMS42Ni0yLjUzMy0xLjI3MS04LjU3NS01LjYwNS0xMS41NTRsLTIuMzM0LTEuNjA0LTM5LjM2Mi0uMTA2Yy0yMS42NS0uMDU4LTM5LjM2My0uMDM0LTM5LjM2My4wNTVzLjI2OS42NzUuNTk4IDEuMzA1YzEuNzQ2IDMuMzUtLjUwNyA2Ljk0Ni00LjM1MyA2Ljk0Ni0zLjQ4NiAwLTUuODE2LTMuNTQ3LTQuNTExLTYuODY4bC42MDItMS41MzJoLTEuMjY4Yy0uNjk3IDAtMi4wMi4zNzMtMi45MzkuODI4bTQyLjA3MSAyNS40MjNjLTE2LjMxMSAyLjM4Mi0zMS40MDkgNy42MjgtNDEuMSAxNC4yODEtNC4wNzMgMi43OTYtMy44ODcgMi4yNzItMi4wMzQgNS43MzEgNC43NTkgOC44ODEgMTIuMjMzIDE3LjA3NyAyNC45MyAyNy4zMzcgMTAuNTMxIDguNTA5IDEyLjc4MSAxMC45ODIgMTUuODUyIDE3LjQxOSAzLjIzOSA2Ljc5IDMuMTUyIDUuODIgMy4xNTIgMzUuMTgxdjI2bC0uOTMxIDEuODkxYy0uNTEzIDEuMDQtMS44MDMgMi42NzUtMi44NjggMy42MzItMS43NzggMS41OTgtMy4xMjYgMi4yODctMTAuNDAxIDUuMzEyLTE5Ljc3MiA4LjIyMi0zMS45OTEgMTYuMTM2LTM1LjIyMyAyMi44MTMtMi40ODEgNS4xMjUuMzcyIDEzLjE3OCA1Ljc5NSAxNi4zNTZsMS43MjEgMS4wMDkgNDUuMTU0LS4xMDZMMjQ1IDMwM2wxLjgzNy0xLjA4YzQuNzM5LTIuNzg2IDcuMjQzLTkuNjExIDUuMzkyLTE0LjY5NS0yLjMxOC02LjM2Ni0xMi4xMDktMTMuMjM1LTMxLjIyOS0yMS45MS0xMy43OTYtNi4yNTktMTUuMjg2LTcuMjExLTE3LjMxNi0xMS4wNkwyMDIuNiAyNTIuMnYtMjUuOGMwLTM2LjUxLjI2Ni0zNy4yNTkgMTguNjU4LTUyLjYwMSAxNy4yMzktMTQuMzc5IDMwLjM0Mi0zMC40NjUgMzAuMzQyLTM3LjI0OCAwLTIuMTk2LTEzLjk4MS03LjA2Mi0yNi40LTkuMTg5LTUuOTc5LTEuMDIzLTI1LjA2LTEuNzQ1LTI5LjQtMS4xMTFtLjQgMy4xNzJjLS4yMi4wODktMS45OTguNjItMy45NTEgMS4xODItOC41MjggMi40NTItMjMuNTEgMTAuMDkzLTI0LjQxNSAxMi40NTEtLjEzOS4zNjEuODg0IDIuMTYgMi41NjQgNC41MTQgNC4yNjYgNS45NzYgNC45NjggOC43MTYgMi42MjYgMTAuMjUxLTEuMzA0Ljg1NC0yLjUzNi40NDMtNC45MjEtMS42NDMtMS43ODEtMS41NTgtNi4xMDMtNi44NzktNi4xMDMtNy41MTMgMC0uMTMxLS43Mi0xLjM1Mi0xLjYtMi43MTQtMi4wMTktMy4xMjMtMi4xMDctMi43NyAxLjMtNS4xOTIgNS4zMjUtMy43ODcgMTIuMDg3LTYuNTU4IDIyLjM3Mi05LjE3IDYuMDg4LTEuNTQ2IDE0LjE5My0yLjk5MyAxMi4xMjgtMi4xNjZtLTUuMjI3IDE2LjIzOGMxLjgxOS44MjggMS42NSAzLjU2LS4yNTcgNC4xNjYtMi4xNjUuNjg3LTMuNzA1LTIuNjg5LTEuODI3LTQuMDA0IDEuMDYtLjc0My44NDctLjcyNiAyLjA4NC0uMTYybS05LjA1MyAxNS4yMTljLjY2NC42NjQuNjAzIDIuOTItLjA5NiAzLjUtLjk0MS43ODEtMi43MzEuMzQxLTMuMzg4LS44MzQtMS4xNDYtMi4wNTEgMS44MjUtNC4zMjUgMy40ODQtMi42NjZtNzkuODggMTQuNDJjNy40MDYgMTYuMTc1IDcuMTkzIDM1LjU2Ny0uNTczIDUyLjEzOS0xLjg0MSAzLjkyOC0xLjY5NSAzLjkyOS01LjIyNy0uMDUzLTMuMDE3LTMuNDAzLTExLjcwMS0xMS41Mi0xOC42LTE3LjM4Ni01LjkxOS01LjAzMy04LjYtNy42MTQtOC42LTguMjc4IDAtLjI4IDEuOTI5LTIuMDg3IDQuMjg3LTQuMDE1IDEwLjI3NS04LjQwNiAyMC42ODEtMTguMzU2IDI0LjQ4LTIzLjQwNyAyLjIzNC0yLjk3MiAyLjQzNi0yLjkyNCA0LjIzMyAxbS0xMTguNy40YzQuMjk5IDUuMDkxIDEyLjQwNyAxMi44NjkgMTkuOSAxOS4wODkgMy43NCAzLjEwNCA3LjA2MSA2LjAxOCA3LjM4IDYuNDc1LjY4Ni45ODIgMS41NDguMTIxLTExLjM5MiAxMS4zOS04LjAzMyA2Ljk5Ny0xMy4wNTIgMTEuODI0LTE2LjUxNCAxNS44OC0xLjYyMiAxLjkwMS0xLjc4OCAxLjc4Ny00LjA1NC0yLjc4Ny03LjM3NC0xNC44ODEtNy40NTItMzQuMTA2LS4yMDEtNDkuNjQ3IDIuMDctNC40MzcgMS41MTItNC4zOTEgNC44ODEtLjRtLTI0LjQ0MSA2LjAwOGMtMi4yMTMgOC44MTktMi41OTkgMjMuMDA0LS44ODggMzIuNjkyLjI5MSAxLjY1LjQ4NyAzLjA1LjQzNSAzLjExMS0uMzAzLjM1Ni0zMy40MzYtNC44MzgtMzUuMjQxLTUuNTI0LTIuMTk4LS44MzYtMi43OTYtMjIuNzcyLS42NzYtMjQuODI2LjI5Ni0uMjg4IDIuNzY3LS43NjUgMTguMzExLTMuNTM1IDE4LjE0Ni0zLjIzNCAxOC4zOTYtMy4yNiAxOC4wNTktMS45MThtMTY2LjUwMS0uNTE2YzEuMTM4LjIxNiA2LjA2OCAxLjAzMSAxMC45NTUgMS44MTEgOC41MjMgMS4zNjEgMTcuNjk0IDMuMDU0IDIwLjcxNSAzLjgyNSAzLjg0Ni45ODIgMy43NDEgMjQuNjkzLS4xMTIgMjUuMzU2LTEyLjY1OCAyLjE3OS0zNC4zODggNS40MjItMzQuNjczIDUuMTc0LS4wODUtLjA3My4xNTMtMS45NzkuNTI5LTQuMjMzIDEuNzQyLTEwLjQ1OCAxLjM5LTIzLjk1Ni0uODI2LTMxLjYyNS0uMjM5LS44MjcuMzc5LS44ODMgMy40MTItLjMwOE0yMDQgMjY0YzAgLjIyLS40MTkuNC0uOTMuNC0yLjExMyAwLTkuNjM2IDIuNjI0LTE0Ljk1NiA1LjIxNi0xMy43NjEgNi43MDctMjEuNDg1IDEzLjY3MS0yNi4yNjMgMjMuNjgxLTIuNTA0IDUuMjQ3LTYuNDA2IDUuOTAzLTguNjc0IDEuNDU4LTQuMDM4LTcuOTE1IDkuMjQ0LTIwLjA3IDMwLjAyMy0yNy40NzcgMy40ODItMS4yNDEgMTIuMjA3LTIuOTY0IDE2LjU4OS0zLjI3NWw0LjExMS0uMzQ0Yy4wNTUtLjAzMi4xLjEyMS4xLjM0MW0tMTIuNCAyMi40YzEuNzMzIDEuNzMzLjM1MiA1LjItMi4wNzIgNS4yLTEuMTU3IDAtMi43MjgtMS43ODktMi43MjgtMy4xMDYgMC0yLjQ4NCAzLjA3MS0zLjgyMyA0LjgtMi4wOTRtLTE3LjgyOSAzLjQyOWMxLjgwOSAxLjgwOC0uNjggNC41OTctMi45OTcgMy4zNTctLjg4Ny0uNDc1LTEuMDc2LTIuNzI0LS4yOTQtMy41MDYuNjgtLjY4IDIuNTQ4LS41OTUgMy4yOTEuMTQ5TTEzMi44IDMxNC44NWMyNC4xNSAyMi42NCA4NC42ODkgMjcuNDMyIDEyMC40MjEgOS41MzQgNS40NDUtMi43MjggMTQuOTExLTkuNTg4IDE1Ljk3Ni0xMS41NzlsLjQzMS0uODA1LTY5LjkxNC4wMTktNjkuOTE0LjAxOXoiIGZpbGw9IiMxNzMyNDEiLz48L3N2Zz4=",
18 html_favicon_url = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxjaXJjbGUgY3k9IjE5Ny41IiBjeD0iMjAwLjUiIHN0cm9rZT0iIzAwMCIgZmlsbD0iI2ZmZiIgcj0iMTUyLjUiLz48cGF0aCBkPSJNMTkxLjI0NyAzLjYyNmMtMTAuMDIuNjEtMTAuMDg1LjcxLTEyLjgzOSAxOS40NzYtMS41NDEgMTAuNDk2LTIuMTE2IDExLjU2Ni02LjczMiAxMi41MjMtMTIuNzIyIDIuNjM3LTIwLjg2MyA0Ljg0OS0yOS45ODcgOC4xNDgtMTEuNDUyIDQuMTQtMTkuOTcyIDguMjA5LTMwLjU3IDE0LjU5OS03LjIxMyA0LjM0OS01LjgzOCA0Ljc5Ny0xOC45MDgtNi4xNTgtOS4wODQtNy42MTMtMTAuMDA3LTguMDc3LTEzLjkxNi02Ljk5Mi00LjMyNSAxLjIwMS0yMi42NzUgMTguNDU5LTI1LjAwMyAyMy41MTUtMS43MjUgMy43NDQtMS40MTcgNC40MjggNy4xNDEgMTUuODYzIDguMjQzIDExLjAxNSA4LjEwMSAxMC42MjMgNS4yMzkgMTQuNDEtMTQuMzY2IDE5LjAwNy0yNS4zNjYgNDMuNjAzLTMwLjA2NiA2Ny4yMjUtMS42MDggOC4wODQuNjI1IDYuOTI2LTIxLjEwOCAxMC45NDdDMy44MTIgMTc5LjE1OCAzLjgxNiAxNzkuMTUyIDMuODMzIDE5OGMuMDIgMjAuNDcxLTIuMDg1IDE4LjQ4MyAyMy45NjcgMjIuNjQ0IDYuNDggMS4wMzUgNi40NDMuOTkyIDcuODI1IDkuMTIgMy45OTMgMjMuNDcgMTQuMTU0IDQ4LjEwMiAyNy40ODMgNjYuNjIyIDQuMDk1IDUuNjkgNC43MzcgNy4xNzQgMy44NTMgOC45MDUtLjgyNCAxLjYxMy01LjY1NSA4LjY2Ni05Ljg0NCAxNC4zNzMtNS4xMTkgNi45NzQtNS43NjYgOS41OTItMy4yNjUgMTMuMjIgMS43NjYgMi41NjMgMTMuMDg4IDEzLjc3NiAxNy4zODQgMTcuMjE3IDkuMTcxIDcuMzQ2IDkuNTAxIDcuMjk3IDIyLjU2NC0zLjM0MiAxMS43NDQtOS41NjQgMTAuMzExLTkuMTk4IDE3Ljk4OC00LjU5MiAxNy4wNzQgMTAuMjQ0IDM1LjYzNyAxNy4yOTIgNTcuNTU0IDIxLjg1MiA3LjAyNSAxLjQ2MSA3LjAyMSAxLjQ1MyA5LjY1OSAxNi4wMzEgMi4zMjMgMTIuODM0IDMuMDI0IDE0LjQzNyA2Ljc5OSAxNS41NDIgMi4yMzUuNjU0IDE5Ljg0Ny45OTggMjQuODc0LjQ4NSA3LjgwNS0uNzk2IDcuODU4LS44NzIgMTAuNzMtMTUuNDQyIDIuOTc4LTE1LjExIDIuOTYzLTE1LjA4NyAxMC43MTYtMTYuNjEyIDE5LjMwNC0zLjc5OSAzOC4xNDctMTAuODMzIDU2Ljg3NS0yMS4yMjkgMy45NTgtMi4xOTcgNy41MDEtMy45OTQgNy44NzUtMy45OTQgMS4wMDIgMCA0LjY0OSAyLjcxNCAxMi4wOTEgOSAxMi4xMzggMTAuMjUzIDEzLjU0NiAxMC4wMjEgMjguNjAyLTQuNzIzIDEyLjQ4My0xMi4yMjUgMTMuMDA4LTE0LjE3OSA2LjI1Mi0yMy4yNzctMTEuODQyLTE1Ljk0Ny0xMS42MzMtMTUuNDY0LTguNTk0LTE5Ljg3IDE3LjQwMy0yNS4yMzMgMjUuNjY1LTQ0Ljk3MSAzMC41NTYtNzIuOTkzLjk3MS01LjU2Mi40MzgtNS4zMTUgMTcuMjIzLTcuOTgzIDkuNzk3LTEuNTU3IDExLjMyMi0yLjA3IDEyLjQwOC00LjE3IDIuMTMyLTQuMTIzIDIuMzctMjguMTEzLjMyOS0zMy4yMjMtLjk4NS0yLjQ2Ni0yLjE1Ny0yLjk4OC0xMC4xOTQtNC41MzktMjEuMDU3LTQuMDY1LTE4LjU5Ni0yLjU2OS0yMC43NTEtMTIuNjIyLTQuNzIzLTIyLjAyNy0xMy43NDEtNDIuNTUzLTI2Ljg4OC02MS4yLTYuMDA3LTguNTE5LTYuMDgxLTcuNjA5IDEuMzg0LTE3LjA1NyA4LjczMy0xMS4wNTQgOS42MzMtMTIuNzIyIDguNzEyLTE2LjE0Mi0xLjMyOS00LjkzOC0yMC44Mi0yMy40ODgtMjYuMDY3LTI0LjgwOS0zLjYzOC0uOTE2LTQuNDY4LS40MjgtMTUuNDc4IDkuMTEzLTkuODgyIDguNTYyLTkuMjA5IDguMzUzLTE1LjAxNSA0LjY2Ni0xNS44NDEtMTAuMDYtMzcuMDE4LTE4LjMyMy01OC43NDktMjIuOTI1LTguNzQ1LTEuODUxLTcuNjU2LjE4OS0xMi4wNDgtMjIuNTYxLTEuNDEyLTcuMzE1LTIuNDg2LTguOC02Ljg0OC05LjQ2My0zLjcxNy0uNTY1LTE2LjE3Ni0uNzg0LTIyLjU0OC0uMzk2TTIwOS40IDU1LjIxMWM5Ni4xMTQgNi4zODEgMTU5LjYzMSA5OS42NDIgMTI5LjY2NyAxOTAuMzg5LTMzLjk1NCAxMDIuODMzLTE2NC42NzcgMTMzLjQ1LTI0MS42OTIgNTYuNjA3LTQyLjMzNS00Mi4yNDEtNTQuNTAzLTk5LjE0Mi0zMy4yMzYtMTU1LjQyOSAyMS4yMy01Ni4xODYgODMuODI3LTk1LjY0NiAxNDUuMjYxLTkxLjU2N20tMjIuNiAxMC41ODdjLTI0LjcyNiAyLjI5My00NS4zMzEgMTAuODExLTU1LjI4MSAyMi44NTFsLTEuNjEzIDEuOTUxIDcwLjE0Ny4yIDcwLjI5MS4xMjNjLjg5Ni0uNDgtNy4xOTctNy44MjMtMTIuNTQ0LTExLjM3OS0xNi40NDctMTAuOTQtNDMuOTE3LTE2LjI1OC03MS0xMy43NDZtOTUuNjMxIDI4LjU2OGMzLjc5NCAxMS43OTYgNC4wOTMgMjYuNTc2Ljc1OCAzNy4zNzQtMS4wNTQgMy40MTUtMS43MzUgMy4yNjIgNi4yMDggMS4zOWw2Ljc5OC0xLjYwMiAxLjEzNCAxLjMzNmMzLjIgMy43NyAxMS4wNzEgMTcuNDkzIDExLjA3MSAxOS4zMDIgMCAuNzUyLTQuNDUgNC44NDgtMTQuNiAxMy40NDFsLTExLjA3MiA5LjUxM2MtMS42NTMgMS41NTktMi40ODkgMS41MDQtMi45MDEtLjE4OC0uNTI4LTIuMTcyLTUuMzgxLTExLjU2Mi03Ljk5NC0xNS40NjctMy4xMzUtNC42ODUtMy4wNDktMy41MDItLjY1Ni05LjA2NSA1LjMzMS0xMi4zOSA3LjU4NC0zMS44NjYgNS4zMjMtNDZsLS43MzYtNC42LTkuNTE1LjA2NmMtMTAuNDU2LjA3Mi0xMC4yOTIuMDQ0LTkuMTExIDEuNTQ2IDMuOTIzIDQuOTg4IDUuNTYzIDIwLjA2MyAzLjM0MSAzMC43MDQtMy43MzQgMTcuODcxLTEyLjk3MSAzMS41MjEtMzIuMTM2IDQ3LjQ4OC0xMy41MTIgMTEuMjU2LTE1LjkgMTQuNTU2LTE1LjkzMyAyMi4wMTItLjAzMSA3LjAzNSAyLjMxIDEwLjUzNiAxMy4xOSAxOS43MjkgMTUuMzEgMTIuOTM0IDIzLjEwOCAyMS45NDQgMjguODYxIDMzLjM0MiA3LjY1NiAxNS4xNzEgOS4yMDkgMzMuOTUxIDMuNzMzIDQ1LjE2OS0uNzY3IDEuNTctMS4zOTQgMi45NjUtMS4zOTQgMy4xczQuMTQ0LjI0NCA5LjIxLjI0NGg5LjIxbC4zNTUtLjkzNWMxLjI0MS0zLjI2MyAyLjIzMi0xOC4wMjQgMS42NTItMjQuNjA1LS45OTQtMTEuMjk0LTIuOTUtMTguODYzLTcuMzkxLTI4LjYwOGwtMS40MS0zLjA5NSAyLjQ0Ny0zLjYzNGMyLjg3My00LjI2NiA2LjUwNy0xMS40NDcgOC4zNjItMTYuNTIzLjcyMy0xLjk4IDEuNDQ2LTMuNzU2IDEuNjA2LTMuOTQ2czIuMTUxIDEuMzQ4IDQuNDI1IDMuNDE3YTQ0NyA0NDcgMCAwIDAgOC41MzQgNy41MjdjNy4wOTMgNi4wNjggMTIuNjM1IDExLjI3MyAxMy42NzIgMTIuODM5bC45NjUgMS40NTgtMi41NDYgNS4zNTNjLTIuNzczIDUuODI2LTYuNTU3IDEyLjMxLTguMjAyIDE0LjA1Mi0xLjMzMyAxLjQxMi0xLjUyOSAxLjQwMS05LjA3Ny0uNDk3LTcuMzg2LTEuODU3LTYuODI4LTEuOTU2LTUuOCAxLjAzMSAzLjM1MyA5Ljc0NCAzLjY5OSAyNy4xMTguNzU5IDM4LjA5NC0xLjMwNSA0Ljg3NS0uOTk0IDQuNzE1IDkuMTY1LTQuNyA2Mi45OTQtNTguMzc4IDU5LjMwMy0xNTUuNTQ1LTcuODc3LTIwNy4zNTktMy43OC0yLjkxNS0zLjc4Mi0yLjkxNC0yLjQyOCAxLjI5N00xMTUuNCA5My4wNDRjLTMuMTQ1IDIuMzU1LTguMTQ4IDYuOS0xMy42IDEyLjM1Ni01NS44MTEgNTUuODUtNTAuNSAxNTAuODAyIDExLjEyMyAxOTguODMxIDQuNTE2IDMuNTIgNC42MDMgMy41MjEgMy41MzUuMDY0LTMuMjg0LTEwLjYzNS0zLjIwNS0yNS42MjUuMTk0LTM2LjM4MiAxLjI0LTMuOTI2IDEuOTA2LTMuNzE3LTUuNzQzLTEuNzk5LTcuMzk3IDEuODU1LTYuODIyIDEuOTU4LTkuNDk1LTEuNzA3LTEuNzM2LTIuMzgtNy4wNTItMTIuMDAyLTguMjEtMTQuODYyLTEuNDkyLTMuNjgyLTIuNjM3LTIuMzMgMTYuMzMtMTkuMjg2bDYuMzY0LTUuNzI1YzMuMjE3LTIuOTExIDQuMTAyLTMuMjgyIDQuMTAyLTEuNzIxIDAgMi4yNTEgNC41NTEgMTEuNTUzIDguOTg1IDE4LjM2M2wyLjYyNSA0LjAzMy0xLjk5NiA0LjA5NWMtNi43MzUgMTMuODE5LTkuNDggMzQuOTQ2LTYuNTExIDUwLjA5NmwuNzA2IDMuNiA5LjE4Ny4xMDhjMTEuMDMuMTI5IDEwLjUzMS4yNTggOC44MjgtMi4yNzMtNS4xMTctNy42MDMtNS41OTktMjIuNjc4LTEuMTUyLTM2LjAzIDUuMTY3LTE1LjUxNSAxNS4zNjQtMjguOTI4IDMzLjQxLTQzLjk1MSA5LjAxNy03LjUwNiAxMS4zNjctMTAuNTM2IDEyLjYwOC0xNi4yNTQgMS43MjYtNy45NTYtLjk2OC0xMi44OTQtMTEuODItMjEuNjY1LTI0Ljk5NS0yMC4yMDItMzUuMTc3LTM1Ljk3Mi0zNi45NTUtNTcuMjM2LS44NjQtMTAuMzM4LjI2Ni0xNy41MjQgMy42NTgtMjMuMjYuOTEyLTEuNTQzIDEuMTQyLTIuMjQ0LjgwMi0yLjQ1NC0uNzI0LS40NDgtMTguMTMuMDQ2LTE4LjQzNC41MjItLjU1Ni44NzMtMS41MjkgOC43ODgtMS43ODEgMTQuNDkzLS41OTQgMTMuMzkyIDIuMDIxIDI3LjQ3IDcuMDIyIDM3LjgxMy44NzggMS44MTQgMS40ODIgMy40OTkgMS4zNDQgMy43NDNzLTEuMTkgMS44ODQtMi4zMzYgMy42NDRjLTIuODk1IDQuNDQ1LTYuMTUgMTAuOTktNy45MjcgMTUuOTMzLS4yOTguODMxLS45NjcuMzg1LTUuNjkxLTMuNzg4LTEuMzM1LTEuMTgtNC41NjgtMy45NDUtNy4xODYtNi4xNDUtMTAuNzcyLTkuMDU1LTE0Ljk4Ni0xMy4xMDMtMTQuOTg2LTE0LjM5NCAwLTIuMTg5IDcuMzY5LTE1LjEzMiAxMC41MzYtMTguNTA2IDEuNTI2LTEuNjI1IDIuMTY5LTEuNjM0IDguNjYxLS4xMjQgNS44NTcgMS4zNjIgNS40MDIgMS41MDcgNC42MzEtMS40Ny0zLjIzMy0xMi40NzUtMi44ODgtMjUuNTA2Ljk4My0zNy4xMzkgMS4xNTMtMy40NjQuOTc4LTMuNjExLTEuODExLTEuNTIzbTM4LjMyOSA3Ljc4NGMtNC45MTkgMi40MzUtOC45MTggMTAuMTcxLTYuNTUgMTIuNjcybC44NTIuOWgxMDMuNTUxbC42ODItMS4wNDJjMS42Ni0yLjUzMy0xLjI3MS04LjU3NS01LjYwNS0xMS41NTRsLTIuMzM0LTEuNjA0LTM5LjM2Mi0uMTA2Yy0yMS42NS0uMDU4LTM5LjM2My0uMDM0LTM5LjM2My4wNTVzLjI2OS42NzUuNTk4IDEuMzA1YzEuNzQ2IDMuMzUtLjUwNyA2Ljk0Ni00LjM1MyA2Ljk0Ni0zLjQ4NiAwLTUuODE2LTMuNTQ3LTQuNTExLTYuODY4bC42MDItMS41MzJoLTEuMjY4Yy0uNjk3IDAtMi4wMi4zNzMtMi45MzkuODI4bTQyLjA3MSAyNS40MjNjLTE2LjMxMSAyLjM4Mi0zMS40MDkgNy42MjgtNDEuMSAxNC4yODEtNC4wNzMgMi43OTYtMy44ODcgMi4yNzItMi4wMzQgNS43MzEgNC43NTkgOC44ODEgMTIuMjMzIDE3LjA3NyAyNC45MyAyNy4zMzcgMTAuNTMxIDguNTA5IDEyLjc4MSAxMC45ODIgMTUuODUyIDE3LjQxOSAzLjIzOSA2Ljc5IDMuMTUyIDUuODIgMy4xNTIgMzUuMTgxdjI2bC0uOTMxIDEuODkxYy0uNTEzIDEuMDQtMS44MDMgMi42NzUtMi44NjggMy42MzItMS43NzggMS41OTgtMy4xMjYgMi4yODctMTAuNDAxIDUuMzEyLTE5Ljc3MiA4LjIyMi0zMS45OTEgMTYuMTM2LTM1LjIyMyAyMi44MTMtMi40ODEgNS4xMjUuMzcyIDEzLjE3OCA1Ljc5NSAxNi4zNTZsMS43MjEgMS4wMDkgNDUuMTU0LS4xMDZMMjQ1IDMwM2wxLjgzNy0xLjA4YzQuNzM5LTIuNzg2IDcuMjQzLTkuNjExIDUuMzkyLTE0LjY5NS0yLjMxOC02LjM2Ni0xMi4xMDktMTMuMjM1LTMxLjIyOS0yMS45MS0xMy43OTYtNi4yNTktMTUuMjg2LTcuMjExLTE3LjMxNi0xMS4wNkwyMDIuNiAyNTIuMnYtMjUuOGMwLTM2LjUxLjI2Ni0zNy4yNTkgMTguNjU4LTUyLjYwMSAxNy4yMzktMTQuMzc5IDMwLjM0Mi0zMC40NjUgMzAuMzQyLTM3LjI0OCAwLTIuMTk2LTEzLjk4MS03LjA2Mi0yNi40LTkuMTg5LTUuOTc5LTEuMDIzLTI1LjA2LTEuNzQ1LTI5LjQtMS4xMTFtLjQgMy4xNzJjLS4yMi4wODktMS45OTguNjItMy45NTEgMS4xODItOC41MjggMi40NTItMjMuNTEgMTAuMDkzLTI0LjQxNSAxMi40NTEtLjEzOS4zNjEuODg0IDIuMTYgMi41NjQgNC41MTQgNC4yNjYgNS45NzYgNC45NjggOC43MTYgMi42MjYgMTAuMjUxLTEuMzA0Ljg1NC0yLjUzNi40NDMtNC45MjEtMS42NDMtMS43ODEtMS41NTgtNi4xMDMtNi44NzktNi4xMDMtNy41MTMgMC0uMTMxLS43Mi0xLjM1Mi0xLjYtMi43MTQtMi4wMTktMy4xMjMtMi4xMDctMi43NyAxLjMtNS4xOTIgNS4zMjUtMy43ODcgMTIuMDg3LTYuNTU4IDIyLjM3Mi05LjE3IDYuMDg4LTEuNTQ2IDE0LjE5My0yLjk5MyAxMi4xMjgtMi4xNjZtLTUuMjI3IDE2LjIzOGMxLjgxOS44MjggMS42NSAzLjU2LS4yNTcgNC4xNjYtMi4xNjUuNjg3LTMuNzA1LTIuNjg5LTEuODI3LTQuMDA0IDEuMDYtLjc0My44NDctLjcyNiAyLjA4NC0uMTYybS05LjA1MyAxNS4yMTljLjY2NC42NjQuNjAzIDIuOTItLjA5NiAzLjUtLjk0MS43ODEtMi43MzEuMzQxLTMuMzg4LS44MzQtMS4xNDYtMi4wNTEgMS44MjUtNC4zMjUgMy40ODQtMi42NjZtNzkuODggMTQuNDJjNy40MDYgMTYuMTc1IDcuMTkzIDM1LjU2Ny0uNTczIDUyLjEzOS0xLjg0MSAzLjkyOC0xLjY5NSAzLjkyOS01LjIyNy0uMDUzLTMuMDE3LTMuNDAzLTExLjcwMS0xMS41Mi0xOC42LTE3LjM4Ni01LjkxOS01LjAzMy04LjYtNy42MTQtOC42LTguMjc4IDAtLjI4IDEuOTI5LTIuMDg3IDQuMjg3LTQuMDE1IDEwLjI3NS04LjQwNiAyMC42ODEtMTguMzU2IDI0LjQ4LTIzLjQwNyAyLjIzNC0yLjk3MiAyLjQzNi0yLjkyNCA0LjIzMyAxbS0xMTguNy40YzQuMjk5IDUuMDkxIDEyLjQwNyAxMi44NjkgMTkuOSAxOS4wODkgMy43NCAzLjEwNCA3LjA2MSA2LjAxOCA3LjM4IDYuNDc1LjY4Ni45ODIgMS41NDguMTIxLTExLjM5MiAxMS4zOS04LjAzMyA2Ljk5Ny0xMy4wNTIgMTEuODI0LTE2LjUxNCAxNS44OC0xLjYyMiAxLjkwMS0xLjc4OCAxLjc4Ny00LjA1NC0yLjc4Ny03LjM3NC0xNC44ODEtNy40NTItMzQuMTA2LS4yMDEtNDkuNjQ3IDIuMDctNC40MzcgMS41MTItNC4zOTEgNC44ODEtLjRtLTI0LjQ0MSA2LjAwOGMtMi4yMTMgOC44MTktMi41OTkgMjMuMDA0LS44ODggMzIuNjkyLjI5MSAxLjY1LjQ4NyAzLjA1LjQzNSAzLjExMS0uMzAzLjM1Ni0zMy40MzYtNC44MzgtMzUuMjQxLTUuNTI0LTIuMTk4LS44MzYtMi43OTYtMjIuNzcyLS42NzYtMjQuODI2LjI5Ni0uMjg4IDIuNzY3LS43NjUgMTguMzExLTMuNTM1IDE4LjE0Ni0zLjIzNCAxOC4zOTYtMy4yNiAxOC4wNTktMS45MThtMTY2LjUwMS0uNTE2YzEuMTM4LjIxNiA2LjA2OCAxLjAzMSAxMC45NTUgMS44MTEgOC41MjMgMS4zNjEgMTcuNjk0IDMuMDU0IDIwLjcxNSAzLjgyNSAzLjg0Ni45ODIgMy43NDEgMjQuNjkzLS4xMTIgMjUuMzU2LTEyLjY1OCAyLjE3OS0zNC4zODggNS40MjItMzQuNjczIDUuMTc0LS4wODUtLjA3My4xNTMtMS45NzkuNTI5LTQuMjMzIDEuNzQyLTEwLjQ1OCAxLjM5LTIzLjk1Ni0uODI2LTMxLjYyNS0uMjM5LS44MjcuMzc5LS44ODMgMy40MTItLjMwOE0yMDQgMjY0YzAgLjIyLS40MTkuNC0uOTMuNC0yLjExMyAwLTkuNjM2IDIuNjI0LTE0Ljk1NiA1LjIxNi0xMy43NjEgNi43MDctMjEuNDg1IDEzLjY3MS0yNi4yNjMgMjMuNjgxLTIuNTA0IDUuMjQ3LTYuNDA2IDUuOTAzLTguNjc0IDEuNDU4LTQuMDM4LTcuOTE1IDkuMjQ0LTIwLjA3IDMwLjAyMy0yNy40NzcgMy40ODItMS4yNDEgMTIuMjA3LTIuOTY0IDE2LjU4OS0zLjI3NWw0LjExMS0uMzQ0Yy4wNTUtLjAzMi4xLjEyMS4xLjM0MW0tMTIuNCAyMi40YzEuNzMzIDEuNzMzLjM1MiA1LjItMi4wNzIgNS4yLTEuMTU3IDAtMi43MjgtMS43ODktMi43MjgtMy4xMDYgMC0yLjQ4NCAzLjA3MS0zLjgyMyA0LjgtMi4wOTRtLTE3LjgyOSAzLjQyOWMxLjgwOSAxLjgwOC0uNjggNC41OTctMi45OTcgMy4zNTctLjg4Ny0uNDc1LTEuMDc2LTIuNzI0LS4yOTQtMy41MDYuNjgtLjY4IDIuNTQ4LS41OTUgMy4yOTEuMTQ5TTEzMi44IDMxNC44NWMyNC4xNSAyMi42NCA4NC42ODkgMjcuNDMyIDEyMC40MjEgOS41MzQgNS40NDUtMi43MjggMTQuOTExLTkuNTg4IDE1Ljk3Ni0xMS41NzlsLjQzMS0uODA1LTY5LjkxNC4wMTktNjkuOTE0LjAxOXoiIGZpbGw9IiMxNzMyNDEiLz48L3N2Zz4="
19)]
20#![cfg_attr(docsrs, feature(doc_cfg))]
21#![warn(missing_docs)]
22
23use proc_macro::TokenStream;
24use syn::{DeriveInput, Expr, ItemFn, parse_macro_input};
25
26mod config;
27mod control;
28mod publisher;
29mod sim_main;
30
31/// Creates a `ControlExpr` from a boolean expression, allowing asynchronous
32/// code to efficiently await a specific condition.
33///
34/// This macro is a cornerstone of the `odem-rs` reactive system. It parses the
35/// provided expression, identifies parts of it that refer to reactive data
36/// sources (termed "control variables"), and constructs a `ControlExpr`.
37///
38/// `ControlExpr` implements [`IntoFuture`], meaning its result can be directly
39/// `.await`ed. The future will be ready when the boolean expression evaluates
40/// to `true`. The underlying mechanism uses the [`Waker`] associated with the
41/// current process to re-evaluate the expression only when one of its
42/// identified control variables changes.
43///
44/// # What are *Control Variables*?
45///
46/// A "control variable" is a part of the expression that the `until!`
47/// macro identifies as a reactive data source. Specifically, any expression
48/// segment that implements the `Publisher` trait is treated as a control
49/// variable. This means it can be subscribed to, and it will notify subscribers
50/// (like the `ControlExpr`) when its underlying value or state changes.
51///
52/// The macro identifies control variables based on their structure when they
53/// form a path to a `Publisher`:
54/// * **Paths:** Simple identifiers (e.g., `my_control_var`) or qualified paths
55/// (e.g., `my_module::reactive_data`) that resolve to a `Publisher`.
56/// * **Field Accesses:** Accessing fields of a struct that ultimately yield a
57/// `Publisher` (e.g., `data_struct.control_field`).
58/// * **Index Operations:** Indexing into collections where the element itself
59/// is a `Publisher` (e.g., `control_array[0]`).
60///
61/// These can be combined. For example, `config.settings[exp_no].duration`
62/// would be treated as a single control variable if this entire expression
63/// resolves to a type that implements `Publisher`.
64///
65/// A common reactive primitive is `Control<T>`, which implements `Publisher`
66/// and provides a `Cell`-like API for interior mutability.
67///
68/// ## What is NOT a Control Variable (in terms of triggering updates)?
69///
70/// * **Literals:** Constants like `true`, `false`, `0`, `"hello"`.
71/// * **Non-Reactive Variables:** Variables in the lexical context of the
72/// closure that do not implement `Publisher`. Their values at the time of
73/// evaluation are used.
74/// * **Local Variables:** Variables declared and used inside the closure.
75/// * **Expressions within Index Calculations:** If an index itself is an
76/// expression (e.g., `my_array[some_offset + 1]`), variables used within that
77/// index calculation (like `some_offset`) are not treated as control
78/// variables for the outer expression `my_array[...]`. This is to prevent
79/// dynamic sets of dependencies.
80/// * **Function/Method Call Results:** The results of function or method calls
81/// are not treated as control variables.
82///
83/// # How It Works (Transformation)
84///
85/// The macro transforms the input expression (e.g., `my_control > 10 && another_control.is_full()`)
86/// into roughly the following structure:
87///
88/// ```ignore
89/// ControlExpr::new(
90/// // Tuple of references to identified control variables (Publishers)
91/// (&my_control, &another_control),
92/// |args| { // Closure taking current values/states from control variables
93/// // Original expression, rewritten:
94/// // If `my_control` implements `Expr` (e.g., `Control<T: Copy>`),
95/// // `my_control` is rewritten as `args.0.get() > 10` (conceptual).
96/// // If `another_control` is just a `Publisher`, its state is used directly.
97/// // The macro uses autoref specialization to handle these cases.
98/// (args.0 /* .get() if Expr */) > 10 && (args.1 /* .get() if Expr */).is_full()
99/// }
100/// )
101/// ```
102///
103/// ## `Expr` Trait Convenience
104///
105/// If a control variable (which implements `Publisher`) also implements the
106/// `Expr` trait, the macro provides a convenience:
107/// * For types like `Control<T>` where `T: Copy`, `Expr` is implemented.
108/// * Inside the generated closure, the macro will automatically call the
109/// `Expr::get()` method to retrieve the inner value. This means users can
110/// write `my_control_var > 0` instead of `my_control_var.get() > 0` in the
111/// expression passed to the macro.
112///
113/// ## Error Handling
114///
115/// * **Non-`Publisher` External Variables:** If a non-local identifier (a path
116/// that is not a simple local variable) used in the expression does not
117/// resolve to a type implementing `Publisher`, it is treated like a local
118/// variable. If it does neither implement `Publisher` nor `Expr`, a
119/// compile-time error will be issued. All external dependencies that are
120/// meant to drive the reactivity must be `Publisher`s.
121///
122/// The specialized handling of different expression types (e.g., a direct
123/// `Publisher` versus a `Publisher + Expr`) leverages an autoref specialization
124/// technique to provide a seamless experience.
125///
126/// # Why Control Variables in Index Calculations Are Not Supported
127///
128/// Allowing variables within index expressions (e.g., `slice[index_variable]`)
129/// to be control variables themselves would imply that the set of *other*
130/// control variables the `ControlExpr` depends on could change dynamically if
131/// `index_variable` changes. For example, if `index_variable` changed from `0`
132/// to `1`, the expression would effectively switch its dependency from
133/// `slice[0]` to `slice[1]`.
134///
135/// Supporting such dynamic dependencies would:
136/// 1. Significantly complicate the dispatch and notification mechanisms.
137/// 2. Prevent optimizations related to a fixed set of dependencies.
138/// 3. Make reasoning about the reactive flow more difficult.
139///
140/// Therefore, expressions within an index are evaluated when the `ControlExpr`
141/// is created or re-evaluated, but variables used solely within them do not
142/// register as separate control variables for the overall expression.
143///
144/// # Limitations
145///
146/// * **Maximum Control Variables:** The macro currently supports a maximum of
147/// 12 distinct control variables within a single `until!` invocation.
148/// If more are detected, a compile-time error will occur.
149/// * **Complexity:** While powerful, overuse, or overly complex expressions
150/// within `until!` can make the reactive logic harder to follow.
151///
152/// # Examples
153///
154/// **1. Awaiting a simple `Control<T>` variable change:**
155///
156/// ```
157/// # use odem_rs::prelude::*;
158/// # async fn sim_main(sim: &Sim) {
159/// let i: Control<i32> = Control::new(0);
160///
161/// sim.fork(async {
162/// // In another task or later in the code:
163/// i.set(1);
164/// }).and(async {
165/// // `i.get()` is implicitly called due to `Expr` trait
166/// until!(i > 0).await;
167/// println!("i is now greater than 0!");
168/// }).await;
169/// # }
170/// ```
171/// *Actual expansion:*
172/// `ControlExpr::new((&i,), |args| args.0.get() > 0).await;`
173///
174/// **2. Awaiting a condition involving multiple `Control<bool>` variables:**
175///
176/// ```
177/// # use odem_rs::prelude::*;
178/// # async fn sim_main(sim: &Sim) {
179/// let is_ready = Control::new(false);
180/// let has_permission = Control::new(false);
181///
182/// sim.fork(async {
183/// sim.advance(1.0).await;
184/// is_ready.set(true);
185/// }).and(async {
186/// sim.advance(2.0).await;
187/// has_permission.set(true);
188/// }).and(async {
189/// until!(is_ready && has_permission).await;
190/// println!("Both conditions met!");
191/// }).await;
192/// # }
193/// ```
194/// *Actual expansion:*
195/// `ControlExpr::new((&is_ready, &has_permission), |args| args.0.get() && args.1.get()).await;`
196///
197/// **3. Using complex paths to `Control<T>` fields:**
198///
199/// ```
200/// # use odem_rs::prelude::*;
201/// # struct AppConfig { settings: Settings }
202/// # struct Settings { font_size: Control<i32>, dark_mode: Control<bool> }
203/// # async fn sim_main(sim: &Sim) {
204/// let app_config = AppConfig {
205/// settings: Settings {
206/// font_size: Control::new(12),
207/// dark_mode: Control::new(false),
208/// }
209/// };
210/// let min_font_size = 10; // Local non-control variable
211///
212/// // Later...
213///
214/// until!(app_config.settings.font_size > min_font_size && app_config.settings.dark_mode).await;
215/// println!("Font size is adequate and dark mode is enabled!");
216/// # }
217/// ```
218///
219/// **4. Interaction with local, non-control variables:**
220///
221/// ```
222/// # use odem_rs::prelude::*;
223/// # async fn sim_main(sim: &Sim) {
224/// let val: Control<i32> = Control::new(5);
225/// let local_modifier = 2; // Not a Publisher
226/// let enabled_flag = true; // Not a Publisher
227///
228/// until!(val * local_modifier > 10 && enabled_flag).await;
229/// println!("Condition with local variables met!");
230/// # }
231/// ```
232/// Here, `val` is the control variable. The closure captures 'local_modifier'
233/// and 'enabled_flag'. Changes to them after `ControlExpr` creation
234/// won't trigger re-evaluation unless `val` also changes.
235///
236/// **5. Usage in an async function:**
237///
238/// ```
239/// # use odem_rs::prelude::*;
240/// async fn wait_for_signal(signal_strength: &Control<u32>) {
241/// // The current task will sleep until signal_strength.get() is 5 or greater.
242/// until!(signal_strength >= 5).await;
243/// }
244/// ```
245///
246/// [`Waker`]: core::task::Waker
247#[proc_macro]
248pub fn until(input: TokenStream) -> TokenStream {
249 match odem_rs_crate("odem-rs-sync") {
250 Ok(sync) => control::control_expr_impl(parse_macro_input!(input as Expr), sync),
251 Err(msg) => msg,
252 }
253 .into()
254}
255
256/// Derives the `Config`-trait for a structure.
257///
258/// The behavior of the derived `Config` implementation can be customized using
259/// attributes at both the struct level and the field level.
260///
261/// ### Struct-Level Attributes: `#[time(...)]` and `#[rank(...)]`
262///
263/// These attributes can be applied to the struct definition to specify the
264/// `Config::Time` and `Config::Rank` associated types and their default initial
265/// values.
266///
267/// The following syntaxes are supported for `#[time(...)]` (and analogously for
268/// `#[rank(...)]`):
269///
270/// 1. **`#[time = "MyTimeType"]`**:
271/// * Sets `Config::Time` to `MyTimeType`.
272/// * The default time value (returned by `default_time()`) will be
273/// `MyTimeType::default()`.
274/// * `MyTimeType` must be a valid path to a type, enclosed in quotes.
275///
276/// 2. **`#[time(MyTimeType)]`**:
277/// * Sets `Config::Time` to `MyTimeType`.
278/// * The default time value will be `MyTimeType::default()`.
279///
280/// 3. **`#[time(MyTimeType = expression)]`**:
281/// * Sets `Config::Time` to `MyTimeType`.
282/// * The default time value will be the result of evaluating `expression`.
283/// `expression` should be a valid Rust expression that yields a value of
284/// `MyTimeType`.
285///
286/// If no struct-level `#[time]` attribute is provided, `Config::Time` defaults
287/// to `f64`, and `default_time()` is `0.0`. For `rank`, the default type is
288/// `()`.
289///
290/// ### Field-Level Attributes: `#[time]` and `#[rank]`
291///
292/// If a field within the struct is annotated with `#[time]` (or `#[rank]`):
293///
294/// * The **type** of that field becomes the `Config::Time` (or `Config::Rank`)
295/// associated type.
296/// * The **value** of that field becomes the value returned by `default_time()`
297/// (or `default_rank()`).
298///
299/// If multiple fields are annotated with `#[time]` (or `#[rank]`), the derive
300/// macro will use the type and value from the field that appears last in the
301/// struct definition.
302///
303/// ### `Config::Data`
304///
305/// The `Config::Data` associated type is always set to `Self`.
306/// The `global_data()` method returns a reference to `self`.
307///
308/// # Examples
309///
310/// **1. Configuration with default settings:**
311///
312/// ```
313/// # use odem_rs::prelude::*;
314/// #[derive(Config)]
315/// struct ModelConfig;
316///
317/// async fn sim_main(sim: &Sim<ModelConfig>) {
318/// // Config::Time will be the default (f64)
319/// // Config::Rank will be the default (())
320/// // Config::Data will be ModelConfig
321/// }
322/// ```
323///
324/// **2. Configuration with user-defined `Data` (implicit):**
325///
326/// The struct itself becomes the `Data`.
327///
328/// ```
329/// # use odem_rs::prelude::*;
330/// #[derive(Config)]
331/// struct ExperimentData {
332/// participant_id: String,
333/// trial_count: u32,
334/// }
335///
336/// async fn sim_main(sim: &Sim<ExperimentData>) {
337/// // Config::Time: default
338/// // Config::Rank: default
339/// println!("Data: Participant {}, Trials {}",
340/// sim.global().participant_id,
341/// sim.global().trial_count);
342/// }
343/// ```
344///
345/// **3. Configuration with `Time` and `Rank` specified by field attributes:**
346///
347/// ```
348/// # use odem_rs::prelude::*;
349/// #[derive(Config)]
350/// struct TimedRankedConfig {
351/// // The simulator uses the type of `model_time` as Config::Time.
352/// // The value of `model_time` is used by `default_time()`.
353/// #[time]
354/// model_time: i32,
355///
356/// // The simulator uses the type of `process_rank` as Config::Rank.
357/// // The value of `process_rank` is used by `default_rank()`.
358/// #[rank]
359/// process_rank: u8,
360/// }
361///
362/// async fn sim_main(sim: &Sim<TimedRankedConfig>) {
363/// // Config::Time is i32, default_time() returns self.model_time
364/// // Config::Rank is u8, default_rank() returns self.process_rank
365/// }
366/// ```
367///
368/// **4. Configuration with `Time` and `Rank` types specified by struct-level attributes:**
369///
370/// ```
371/// # use odem_rs::prelude::*;
372/// #[derive(Config)]
373/// #[time = "Time<f64>"]
374/// #[rank(u16)]
375/// struct CustomTypedConfig {
376/// setting_value: i32,
377/// }
378///
379/// async fn sim_main(sim: &Sim<CustomTypedConfig>) {
380/// // Config::Time is Time<f64>
381/// // Config::Rank is u16
382/// }
383/// ```
384///
385/// **5. Configuration with `Time` and `Rank` types and specific default values via struct-level attributes:**
386///
387/// ```
388/// # use odem_rs::prelude::*;
389/// #[derive(Config)]
390/// #[time(Time<f64> = hour::new(8.0))]
391/// #[rank(u8 = 100)]
392/// struct ExplicitDefaultsConfig {
393/// max_iterations: u32,
394/// }
395///
396/// async fn sim_main(sim: &Sim<ExplicitDefaultsConfig>) {
397/// // Config::Time is Time<f64>, initial time is hour::new(8.0)
398/// // Config::Rank is u8, default rank is 100
399/// }
400/// ```
401///
402/// **6. Overriding struct-level type with a field-level attribute:**
403///
404/// Field-level attributes take precedence for determining both the type and the
405/// default value.
406///
407/// ```
408/// # use odem_rs::prelude::*;
409/// #[derive(Config)]
410/// #[time = "u64"] // Suggests u64, but the field below overrides.
411/// struct FieldOverrideConfig {
412/// #[time]
413/// model_time: f64,
414/// some_other_data: bool,
415/// }
416///
417/// async fn sim_main(sim: &Sim<FieldOverrideConfig>) {
418/// // Config::Time is f64 due to the #[time] on `model_time`.
419/// // default_time() will return the value of `sim.global().model_time`.
420/// }
421/// ```
422#[proc_macro_derive(Config, attributes(time, rank))]
423pub fn derive_config(input: TokenStream) -> TokenStream {
424 match odem_rs_crate("odem-rs-core") {
425 Ok(core) => config::config_derive_impl(parse_macro_input!(input as DeriveInput), core),
426 Err(msg) => msg,
427 }
428 .into()
429}
430
431/// Derives the `Publisher`-trait for a structure.
432///
433/// The macro allows the attributes of a structure to be annotated with
434/// `#[subscribe]` and generates an implementation of `Publisher` that will
435/// subscribe and unsubscribe to all the annotated attributes. This allows
436/// the structure to be used inside the `until!`-macro.
437///
438/// # Examples
439///
440/// Simple `Publisher`:
441/// ```
442/// # use odem_rs::prelude::*;
443/// # async fn sim_main() {
444/// #[derive(Publisher)]
445/// struct Foo(#[subscribe] Control<bool>);
446///
447/// impl Foo {
448/// fn is_false(&self) -> bool {
449/// !self.0.get()
450/// }
451/// }
452///
453/// let foo = Foo(Control::new(true));
454///
455/// // will wake up, once another part of the simulation sets
456/// // the inner `Control` to `true`
457/// until!(foo.is_false()).await;
458/// # }
459/// ```
460///
461/// Multiple fields:
462/// ```
463/// # use odem_rs::prelude::*;
464/// #[derive(Publisher)]
465/// struct Foo {
466/// field1: i32,
467/// #[subscribe]
468/// field2: Control<i32>,
469/// #[subscribe]
470/// field3: Control<bool>,
471/// }
472/// ```
473///
474/// Nesting of `Publisher` is possible, and generics are permitted:
475/// ```
476/// # use odem_rs::prelude::*;
477/// # #[derive(Publisher)] struct Foo;
478/// #[derive(Publisher)]
479/// struct Bar<T: ?Sized> {
480/// #[subscribe]
481/// foo: Foo,
482/// data: T,
483/// }
484/// ```
485///
486/// Generic `Publisher` are also supported and qualify their implementation
487/// using an extended `where`-bound for the individual subscriber fields.
488/// ```
489/// # use odem_rs::prelude::*;
490/// #[derive(Publisher)]
491/// struct Bar<T> {
492/// #[subscribe]
493/// maybe_publisher: T
494/// }
495/// ```
496#[proc_macro_derive(Publisher, attributes(subscribe))]
497pub fn derive_publisher(input: TokenStream) -> TokenStream {
498 match odem_rs_crate("odem-rs-sync") {
499 Ok(sync) => {
500 publisher::publisher_derive_impl(parse_macro_input!(input as DeriveInput), sync)
501 }
502 Err(msg) => msg,
503 }
504 .into()
505}
506
507/// Generates a synchronous main function that sets up a simulator, runs the
508/// provided asynchronous simulation logic, and handles the results.
509///
510/// The user's function to which the attribute is applied **must**:
511/// 1. Be an `async fn`.
512/// 2. Accept a simulation context as its first argument (e.g., `sim: &Sim`).
513/// This argument is provided by the `simulator.run()` call.
514/// 3. Any later arguments to the user's `async fn` will become arguments
515/// of the generated synchronous wrapper function.
516/// 4. The return type of the user's `async fn` will be the return type of the
517/// generated synchronous wrapper, with specialized handling for `Result`
518/// types (see below).
519///
520/// The attribute can optionally take an expression as an argument, which will
521/// be used to initialize the configuration (e.g.,
522/// `#[odem_rs::main(custom_init())]`). The initialization expression can also
523/// refer to the arguments passed during the function call. If no argument is
524/// provided, the configuration is default-constructed.
525///
526/// # Generated Code Structure
527///
528/// The macro transforms the user's `async fn sim_main(sim: &Sim, arg1: T) -> R`
529/// into a synchronous function like:
530///
531/// ```ignore
532/// pub fn sim_main(arg1: T) -> R {
533/// use odem_rs::core::simulator::{Simulator, details::*};
534///
535/// // Simulator setup
536/// let simulator = Simulator::new(init_expr_or_default);
537///
538/// // Running the simulation
539/// let result = simulator.run(async move |sim: &Sim| {
540/// // User's original async fn
541/// });
542///
543/// // Specialized result handling
544/// (&result).classify().unwrap(result)
545/// }
546/// ```
547///
548/// # Specialized `Result` Handling
549///
550/// The generated code uses a `classify().unwrap()` pattern on the `Result`
551/// returned by `simulator.run()`. This leverages helper traits and
552/// implementations in `odem_rs::core::simulator::details` to achieve
553/// compile-time specialization adapted from **David Tolnay** and described
554/// [here](https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md):
555///
556/// * **Generic Case**: If the user's `async fn` returns `R` (which becomes
557/// `Result<R, Deadlock>` after `simulator.run()`), or `Result<R, Err>`
558/// (becoming `Result<Result<R, Err>, Deadlock>`), and `Err` cannot be
559/// converted from `Deadlock`, the `unwrap` call will return `R` or
560/// `Result<R, Err>` respectively, and panic if `Deadlock` occurred.
561///
562/// * **Specialized Case**: If the user's `async fn` returns `Result<R, Err>`
563/// (becoming `Result<Result<R, Err>, Deadlock>` after `simulator.run()`),
564/// *and* `Err` implements `From<Deadlock>`, the `unwrap` call will convert
565/// the `Deadlock` into an `Err` if the simulation run results in
566/// `Err(Deadlock)`. The final return type in this case is `Result<R, Err>`,
567/// and the function *does not panic* on `Deadlock`, instead folding it into
568/// `Err`.
569///
570/// This allows for cleaner error handling by automatically propagating the
571/// simulator-specific `Deadlock` error into the user's defined error type,
572/// provided the necessary `From` trait is implemented. For example,
573/// `SimResult<R>` implements `From<Deadlock>` for its error variant.
574///
575/// # Examples
576///
577/// **1. Basic simulation with no extra arguments and no return type**
578///
579/// ```no_run
580/// # use odem_rs::prelude::*;
581/// #[odem_rs::main]
582/// async fn main(sim: &Sim) {
583/// // simulation logic using `sim`
584/// }
585/// ```
586///
587/// **2. Simulation with arguments and custom simulator initialization**
588///
589/// ```no_run
590/// # use odem_rs::prelude::*;
591/// # #[derive(Config)] struct MyConfig;
592/// # fn my_custom_sim_config(_: i32) -> MyConfig { MyConfig }
593/// #[odem_rs::main(my_custom_sim_config(steps))]
594/// async fn with_args(sim: &Sim<MyConfig>, steps: i32) -> String {
595/// "simulation logic using `sim` and `steps`, returning a `String`".to_string()
596/// }
597///
598/// fn main() {
599/// let _: String = with_args(10);
600/// }
601/// ```
602///
603/// **3. Handling `Result` with a generic error (panics on `Deadlock`)**
604///
605/// ```should_panic
606/// # use odem_rs::prelude::*;
607/// #[derive(Debug, PartialEq)]
608/// struct CustomError(String); // Does NOT implement From<Deadlock>
609///
610/// #[odem_rs::main]
611/// async fn with_custom_error(sim: &Sim) -> Result<String, CustomError> {
612/// sleep().await;
613/// Ok("Data".to_string())
614/// }
615///
616/// fn main() {
617/// let result = with_custom_error(); // panics due to the `sleep().await`
618/// assert_eq!(result, Ok("Data".to_string()));
619/// }
620/// ```
621///
622/// **4. Specialized `Result` handling (converts `Deadlock` to `UserError`)**
623///
624/// This example uses `SimResult`, which implements `From<Deadlock>`.
625///
626/// ```
627/// # use odem_rs::prelude::*;
628/// # #[derive(Config, Default)] struct MyConfig;
629/// #[odem_rs::main]
630/// async fn with_specialized_error(sim: &Sim<MyConfig>) -> SimResult<String> {
631/// sleep().await;
632/// Ok("Data".to_string())
633/// }
634///
635/// fn main() {
636/// match with_specialized_error() {
637/// Ok(value) => println!("Success: {}", value),
638/// Err(err) => {
639/// // If sleep().await was called, and Deadlock was converted,
640/// // this arm would be hit.
641/// println!("Handled SimError: {}", err);
642/// }
643/// }
644/// }
645/// ```
646#[proc_macro_attribute]
647pub fn sim_main(attr: TokenStream, code: TokenStream) -> TokenStream {
648 match odem_rs_crate("odem-rs-core") {
649 Ok(core) => sim_main::sim_main_impl(
650 if !attr.is_empty() {
651 Some(parse_macro_input!(attr as Expr))
652 } else {
653 None
654 },
655 parse_macro_input!(code as ItemFn),
656 core,
657 ),
658 Err(msg) => msg,
659 }
660 .into()
661}
662
663/// Helper function to locate the name of the specific `odem-rs` crate.
664///
665/// This function handles calls from within the corresponding crate itself, as
666/// well as calls including the main `odem-rs` crate or the specific crate, even
667/// if the dependency has been renamed in the `Cargo.toml`.
668fn odem_rs_crate(name: &str) -> Result<proc_macro2::TokenStream, proc_macro2::TokenStream> {
669 use proc_macro_crate::{FoundCrate, crate_name};
670 use proc_macro2::Span;
671 use quote::quote;
672 use syn::Ident;
673
674 // check if the `odem-rs` crate is in the list of cargo dependencies
675 if let Ok(odem_rs) = crate_name("odem-rs") {
676 let odem_rs = match odem_rs {
677 FoundCrate::Itself => Ident::new("odem_rs", Span::call_site()),
678 FoundCrate::Name(name) => Ident::new(&name, Span::call_site()),
679 };
680 let suffix = Ident::new(name.rsplit('-').next().unwrap(), Span::call_site());
681 Ok(quote!(#odem_rs::#suffix))
682 } else if let Ok(found) = crate_name(name) {
683 // handle the crate itself being pulled in
684 Ok(match found {
685 FoundCrate::Itself => {
686 // could be `crate` since we're probably in a unit test function
687 // but is more robust for doctests that are compiled in a
688 // separate crate, despite belonging to the same library;
689 // my crates include themselves via `extern crate self as name`
690 let name = Ident::new(&name.replace('-', "_"), Span::call_site());
691 quote!(#name)
692 }
693 FoundCrate::Name(name) => {
694 let name = Ident::new(&name, Span::call_site());
695 quote!(#name)
696 }
697 })
698 } else {
699 Err(quote!(compile_error!(concat!(
700 "neither `odem-rs` nor `", #name, "` found in dependency chain; \
701 did you include `odem-rs` in your Cargo.toml?"
702 ))))
703 }
704}