#![feature(import_trait_associated_functions)] #![feature(associated_type_defaults)] #![feature(impl_trait_in_assoc_type)] #![feature(rustc_attrs)] #![feature(where_clause_attrs)] #![feature(structural_match)] #![feature(negative_impls)] #![feature(array_windows)] #![feature(box_into_inner)] #![feature(slice_ptr_get)] #![feature(ub_checks)] #![feature(pointer_like_trait)] #![feature(pin_coerce_unsized_trait)] #![feature(dispatch_from_dyn)] #![feature(coerce_unsized)] #![feature(unsize)] #![feature(cfg_sanitize)]
#![feature(non_null_from_ref)]
mod daemonic_syscall {
use crate::Timestamp;
use crate::GlassState;
use crate::Position;
struct SyscallContext; struct JustificationError; struct ElevationError; pub trait DaemonicSyscall: Send + Sync {
fn name(&self) -> &'static str;
fn position(&self) -> Position;
type FailureState: for<'glass_state> GlassState<'glass_state>;
}
pub(crate) trait ObservationSyscall: DaemonicSyscall {
type Observed;
fn observe(&self) -> Result<Self::Observed, Self::FailureState>;
}
pub(crate) trait WriteSyscall: DaemonicSyscall {
type WriteData;
type Justification: WriteJustification;
fn write(
&self,
data: Self::WriteData,
justification: Self::Justification,
) -> Result<(), Self::FailureState>;
fn requires_peer_review(&self, context: &SyscallContext) -> bool {
context.state_corrupted()
}
}
pub(crate) trait ElevatedSyscall: DaemonicSyscall {
type ElevationProof: ElevationProof;
type Justification: WriteJustification;
fn execute_elevated(
&self,
proof: Self::ElevationProof,
justification: Self::Justification,
) -> Result<(), Self::FailureState>;
fn requires_peer_review(&self, _context: &SyscallContext) -> bool {
true
}
}
pub trait WriteJustification: Send + Sync {
fn reason(&self) -> &str;
fn authorizer(&self) -> &dyn Authorizer;
fn timestamp(&self) -> Timestamp;
fn verify(&self) -> Result<(), JustificationError>;
}
pub trait ElevationProof: Send + Sync {
fn elevation_type(&self) -> ElevationType;
fn is_valid(&self) -> bool;
fn verify(&self) -> Result<(), ElevationError>;
}
pub enum ElevationType {
Root,
Capability(CapabilitySet),
EntityPrivilege(EntityId),
TemporaryElevation { expires: Timestamp },
}
struct CapabilitySet; struct EntityId; pub trait Authorizer: Send + Sync {
fn id(&self) -> AuthorizerId;
fn can_authorize(&self, syscall: &dyn DaemonicSyscall<FailureState=()>) -> bool; }
pub trait PeerReviewable {
fn request_review(&self, mesh: &dyn MeshNetwork) -> ReviewRequest;
fn review_status(&self, request: &ReviewRequest) -> ReviewStatus;
fn execute_after_review(&self, approval: ReviewApproval) -> Result<(), Self::FailureState>;
}
pub enum ReviewStatus {
Pending { required: usize, received: usize },
Approved(ReviewApproval),
Rejected { reason: String },
TimedOut,
NoMesh,
}
pub struct ReviewApproval {
pub approvers: Vec<EntityId>,
pub timestamp: Timestamp,
pub quorum_met: bool,
}
impl<S: WriteSyscall + PeerReviewable> S {
pub fn write_with_review(
&self,
data: Self::WriteData,
justification: Self::Justification,
mesh: Option<&dyn MeshNetwork>,
context: &SyscallContext,
) -> Result<(), WriteError<Self::FailureState>> {
if self.requires_peer_review(context) {
match mesh {
Some(m) => {
let request = self.request_review(m);
match self.review_status(&request) {
ReviewStatus::Approved(approval) => {
self.execute_after_review(approval)?;
}
ReviewStatus::Rejected { reason } => {
return Err(WriteError::ReviewRejected(reason)); }
ReviewStatus::NoMesh => {
self.write(data, justification)?;
}
_ => return Err(WriteError::ReviewPending),
}
}
None => {
self.write(data, justification)?;
}
}
} else {
self.write(data, justification)?;
}
Ok(())
}
}
}
mod mesh {
use crate::{DaemonicBinary, DaemonicError};
pub trait MeshNetwork: Send + Sync {
fn local_id(&self) -> EntityId;
fn peers(&self) -> &[EntityId];
fn send<FORMAT, PARTIAL>(&self, peer: EntityId, data: impl DaemonicBinary) -> Result<(), MeshError>;
fn receive<FORMAT, PARTIAL>(&self) -> Result<(EntityId, dyn DaemonicBinary<Error=impl DaemonicError<FORMAT, PARTIAL>>), MeshError>;
fn request_review(&self, operation: &dyn PeerReviewable) -> ReviewRequest;
fn check_review(&self, request: &ReviewRequest) -> ReviewStatus;
}
pub struct NoMesh;
impl MeshNetwork for NoMesh {
fn local_id(&self) -> EntityId {
EntityId::solo()
}
fn peers(&self) -> &[EntityId] {
&[]
}
fn send<FORMAT, PARTIAL>(&self, _: EntityId, _: Box<dyn DaemonicBinary<Error=impl DaemonicError<FORMAT, PARTIAL>>>) -> Result<(), MeshError> {
Err(MeshError::NoPeers)
}
fn receive<FORMAT, PARTIAL>(&self) -> Result<(EntityId, dyn DaemonicBinary<Error=impl DaemonicError<FORMAT, PARTIAL>>), MeshError> {
Err(MeshError::NoPeers)
}
fn request_review(&self, _: &dyn PeerReviewable) -> ReviewRequest {
ReviewRequest::no_mesh()
}
fn check_review(&self, _: &ReviewRequest) -> ReviewStatus {
ReviewStatus::NoMesh
}
}
}
mod doc_template;
mod opaque_dependencies;
pub(crate) mod daemonic {
use daemonic_core::DaemonicClock;
use daemonic_core::DaemonicCore;
use daemonic_contract::DaemonicContract;
use crate::daemonic::daemonic_contract::DaemonicBinary;
use crate::{DaemonicError, Position};
pub(crate) trait Daemonic<FORMAT, PARTIAL>: DaemonicCore<FORMAT, PARTIAL> + DaemonicContract<FORMAT, PARTIAL> {
#[must_use]
fn id(&self) -> DaemonicID<FORMAT, PARTIAL>;
#[must_use]
fn position(&self) -> Position;
}
pub(crate) mod daemonic_core {
use crate::DaemonicError;
use crate::ErrorContext;
use observation::DaemonicObservation;
use observer::*;
pub(crate) trait DaemonicCore<FORMAT, PARTIAL>: DaemonicClock<FORMAT, PARTIAL> + DaemonicObservation<FORMAT, PARTIAL> {
type Clock: DaemonicClock<FORMAT, PARTIAL>;
type Observer: DaemonicObserver<FORMAT, PARTIAL>;
}
pub(crate) mod observer {
use crate::daemonic::{Daemonic, DaemonicID};
use crate::daemonic::daemonic_contract::DaemonicContract;
use crate::{DaemonicError, ErrorContext};
use crate::daemonic::daemonic_core::DaemonicClock;
pub(crate) trait DaemonicObserver<FORMAT, PARTIAL>: Daemonic<FORMAT, PARTIAL> {
type Contract: DaemonicContract<FORMAT, PARTIAL>;
type Clock: DaemonicClock<FORMAT, PARTIAL>;
fn id(&self) -> DaemonicID<FORMAT, PARTIAL>;
fn broken_sword<FORMAT, PARTIAL>(&self, err: Box<dyn ErrorContext>) -> impl DaemonicError<FORMAT, PARTIAL> { None }
}
}
use super::super::Position;
pub use clock::{DaemonicClock, SteerableClock, SteppableClock, UncertainClock};
use crate::daemonic::Daemonic;
use crate::daemonic::daemonic_contract::DaemonicContract;
pub(crate) mod clock {
use crate::DaemonicError;
use std::fmt::Debug;
mod types {
use std::fmt;
use std::ops::{Add, Sub};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Timestamp(u64);
impl Timestamp {
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn zero() -> Self {
Self(0)
}
pub const fn one() -> Self {
Self(1)
}
pub const fn as_u64(self) -> u64 {
self.0
}
pub const fn is_zero(self) -> bool {
self.0 == 0
}
pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
assert!(self >= earlier, "earlier must be <= self");
self.0 - earlier.0
}
pub fn checked_elapsed_since(self, earlier: Timestamp) -> Option<u64> {
if self >= earlier {
Some(self.0 - earlier.0)
} else {
None
}
}
pub fn saturating_sub(self, other: Timestamp) -> u64 {
self.0.saturating_sub(other.0)
}
}
impl Add<u64> for Timestamp {
type Output = Timestamp;
fn add(self, rhs: u64) -> Timestamp {
Timestamp(self.0 + rhs)
}
}
impl Sub for Timestamp {
type Output = u64;
fn sub(self, rhs: Timestamp) -> u64 {
self.0 - rhs.0
}
}
impl Sub<u64> for Timestamp {
type Output = Timestamp;
fn sub(self, rhs: u64) -> Timestamp {
Timestamp(self.0 - rhs)
}
}
impl From<u64> for Timestamp {
fn from(value: u64) -> Self {
Timestamp(value)
}
}
impl From<Timestamp> for u64 {
fn from(ts: Timestamp) -> u64 {
ts.0
}
}
impl fmt::Display for Timestamp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Duration(u64);
impl Duration {
pub const fn new(ticks: u64) -> Self {
Self(ticks)
}
pub const fn zero() -> Self {
Self(0)
}
pub const fn as_u64(self) -> u64 {
self.0
}
pub const fn is_zero(self) -> bool {
self.0 == 0
}
}
impl From<u64> for Duration {
fn from(ticks: u64) -> Self {
Duration(ticks)
}
}
impl From<Duration> for u64 {
fn from(d: Duration) -> u64 {
d.0
}
}
impl fmt::Display for Duration {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} ticks", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_timestamp_creation() {
let ts = Timestamp::new(42);
assert_eq!(ts.as_u64(), 42);
let zero = Timestamp::zero();
assert!(zero.is_zero());
assert_eq!(zero.as_u64(), 0);
}
#[test]
fn test_timestamp_arithmetic() {
let t1 = Timestamp::new(100);
let t2 = Timestamp::new(200);
assert_eq!(t1 + 50, Timestamp::new(150));
assert_eq!(t2 - t1, 100);
assert_eq!(t2 - 50, Timestamp::new(150));
}
#[test]
fn test_timestamp_elapsed() {
let t1 = Timestamp::new(100);
let t2 = Timestamp::new(200);
assert_eq!(t2.elapsed_since(t1), 100);
assert_eq!(t2.checked_elapsed_since(t1), Some(100));
assert_eq!(t1.checked_elapsed_since(t2), None);
}
#[test]
fn test_timestamp_ordering() {
let t1 = Timestamp::new(100);
let t2 = Timestamp::new(200);
assert!(t1 < t2);
assert!(t2 > t1);
assert_eq!(t1, Timestamp::new(100));
}
#[test]
fn test_timestamp_conversions() {
let value: u64 = 42;
let ts: Timestamp = value.into();
let back: u64 = ts.into();
assert_eq!(back, value);
}
}
}
use types::*;
pub trait DaemonicClock<'clock, FORMAT, PARTIAL>: Clone + Send + Sync + Debug + 'clock {
fn now(&self) -> Result<Timestamp, impl DaemonicError<FORMAT, PARTIAL>>;
fn tick(&self) -> Result<Timestamp, impl DaemonicError<FORMAT, PARTIAL>>;
fn sync(&self, external: Timestamp) -> Result<Timestamp, impl DaemonicError<FORMAT, PARTIAL>>;
fn compare(&self, a: Timestamp, b: Timestamp) -> std::cmp::Ordering {
a.cmp(&b) }
fn is_zero(&self, ts: Timestamp) -> bool {
ts.is_zero() }
fn duration_between(
&self,
a: Timestamp,
b: Timestamp,
) -> Result<Duration, impl DaemonicError<FORMAT, PARTIAL>>;
fn clock_type<'clocktype>(&self) -> &'clocktype str;
fn is_healthy(&self) -> bool;
}
pub trait SteerableClock<FORMAT, PARTIAL>: for<'steerableclock> DaemonicClock<'steerableclock, FORMAT, PARTIAL> {
fn set_frequency(&self, freq: f64) -> Result<Timestamp, impl DaemonicError<FORMAT, PARTIAL>>;
fn get_frequency(&self) -> Result<f64, impl DaemonicError<FORMAT, PARTIAL>>;
}
pub trait SteppableClock<FORMAT, PARTIAL>: for<'steppableclock> DaemonicClock<'steppableclock, FORMAT, PARTIAL> {
fn step(&self, offset: Duration) -> Result<Timestamp, impl DaemonicError<FORMAT, PARTIAL>>;
}
pub trait UncertainClock: for<'uncertainclock> DaemonicClock<'uncertainclock, FORMAT, PARTIAL> {
fn uncertainty(&self) -> Duration;
fn set_uncertainty(&self, uncertainty: Duration) -> Result<(), impl DaemonicError<FORMAT, PARTIAL>>;
}
}
pub(crate) mod observation {
use std::any::Any;
use std::sync::atomic::AtomicU8;
use crate::{DaemonicCore, IntoDaemonicResult};
use crate::daemonic::daemonic_contract::Partial;
use crate::observer::DaemonicObserver;
use super::super::Daemonic;
pub(crate) trait DaemonicObservation<FORMAT, PARTIAL> {
#[must_use]
fn observe<TARGET>(&self, target: &TARGET) -> impl crate::GlassState;
fn observation_mode(&self) -> ObservationMode {
ObservationMode::Passive(Passive)
}
fn observation_mode_for(&self, observer: &impl DaemonicObserver<FORMAT, PARTIAL>) ->
ObservationMode {
self.observation_mode() }
}
pub(crate) enum ObservationMode {
Active(Active),
Passive(Passive),
}
pub(crate) struct Active<OUTPUT, ERROR, FORMAT = crate::DaemonicResult<OUTPUT, ERROR>, PARTIAL = dyn Partial> {
pub glass_verbosity: AtomicU8,
pub extract_fn: Box<dyn FnOnce()>,
pub extract_object: Option<dyn Extract<FORMAT, PARTIAL>>,
}
pub(crate) struct Passive {
pub glass_verbosity: AtomicU8,
}
trait Extract<FORMAT, PARTIAL>: DaemonicObserver<FORMAT, PARTIAL> {
fn extract_self(&self) -> impl IntoDaemonicResult<FORMAT, PARTIAL>;
fn extract_object() -> impl IntoDaemonicResult<FORMAT, PARTIAL>;
}
pub(crate) mod debug {
use std::any::Any;
use std::fmt::{Debug, Display};
use std::sync::atomic::{AtomicU8, Ordering};
use crate::{DaemonicError, GlassState};
use crate::daemonic::daemonic_contract::DaemonicResult;
use crate::daemonic::daemonic_core::observation::display::DaemonicArgument;
use super::DaemonicObservation;
use super::error::display::DaemonicDisplay;
pub(crate) trait DaemonicDebug<FORMAT, PARTIAL>: DaemonicObservation<FORMAT, PARTIAL>
+ DaemonicDisplay
+ Send
+ Sync
{
fn fmt(&self, f: &mut super::display::DaemonicFormatter<'_>) -> std::fmt::Result;
fn debug(&self, msg: impl DaemonicDisplay) -> impl GlassState;
fn walk_layer(&self, layer: u8, msg: impl DaemonicDisplay);
fn walk_down(&self, layer: u8, msg: impl DaemonicDisplay);
fn walk_up(&self, layer: u8, msg: impl DaemonicDisplay);
fn escalate_to_error<'escalation>(&self, glass: impl GlassState<'escalation>) -> impl DaemonicError<FORMAT, PARTIAL>;
}
static GLASS_VERBOSITY: AtomicU8 = AtomicU8::new(0);
pub fn set_glass_verbosity(level: u8) {
GLASS_VERBOSITY.store(level, Ordering::Relaxed);
}
pub fn glass_verbosity() -> u8 {
GLASS_VERBOSITY.load(Ordering::Relaxed)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Down,
Up,
Lateral,
Mirror,
}
impl Direction {
pub fn symbol(&self) -> &'static str {
match self {
Direction::Down => "↓",
Direction::Up => "↑",
Direction::Lateral => "→",
Direction::Mirror => "∞∞∞",
}
}
}
#[macro_export]
macro_rules! walk_info {
($layer:expr, $($arg:tt)*) => {
println!("[SHADE] [INFO] [layer {}] {}", $layer, format!($($arg)*));
};
}
#[macro_export]
macro_rules! walk_warn {
($layer:expr, $($arg:tt)*) => {
println!("[SHADE] [WARN] [layer {}] {}", $layer, format!($($arg)*));
};
}
#[macro_export]
macro_rules! walk_down {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 2 {
println!("[SHADE] Walking DOWN <↓> [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_call {
($callnumber:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 4 {
println!("[DAEMONIC CALL #{}] Walking [layer ∞∞∞] {}", $callnumber, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_up {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 2 {
println!("[SHADE] Walking UP <↑> [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_lateral {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 1 {
println!("[SHADE] [LATERAL-WALK] <→> [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_layer {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 1 {
println!("[SHADE] [VERBOSE] [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_verbose {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 2 {
println!("[SHADE] [DEBUG] [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_trace {
($layer:expr, $($arg:tt)*) => {
if $crate::walkguard::level() >= 3 {
println!("[SHADE] [TRACE] [layer {}] {}", $layer, format!($($arg)*));
}
};
}
#[macro_export]
macro_rules! walk_break {
($layer:expr, $($arg:tt)*) => {
println!("[SHADE] [DAEMONIC ERROR] [⚡ BREAK] [layer {}] {}", $layer, format!($($arg)*));
};
}
#[macro_export]
macro_rules! walk_boundary {
($from:expr, $to:expr) => {
if $crate::walkguard::level() >= 2 {
let direction = if $to > $from {
"down to"
} else if $to < $from {
"up to"
} else {
"lateral to"
};
println!("[SHADE] [BOUNDARY-WALK] <-> Stepped {} layer {}", direction, $to);
}
};
}
pub struct WalkGuard {
layer: u8,
context: String,
}
impl WalkGuard {
pub fn new(layer: u8, context: impl Into<String>) -> Self {
let context = context.into();
walk_down!(layer, "{}", context);
walk_boundary!(layer.saturating_sub(1), layer);
Self { layer, context }
}
pub fn silent(layer: u8, context: impl Into<String>) -> Self {
Self {
layer,
context: context.into(),
}
}
pub fn call(layer: u8, context: impl Into<String>) -> Self {
Self {
layer,
context: context.into(),
}
}
}
impl Drop for WalkGuard {
fn drop(&mut self) {
walk_boundary!(self.layer, self.layer.saturating_sub(1));
walk_up!(self.layer, "{} complete", self.context);
}
}
}
pub(crate) mod display {
use std::hint::unreachable_unchecked;
use std::fmt::{write, Arguments, Debug, Display, Error, Formatter, FormattingOptions, Write};
use std::marker::PhantomData;
use std::ptr::NonNull;
use crate::DaemonicError;
use super::debug::DaemonicDebug;
#[rustc_on_unimplemented(
on(
any(_Self = "std::path::Path", _Self = "std::path::PathBuf"),
label = "`{Self}` cannot be formatted with the default formatter; call `.display()` on it",
note = "call `.display()` or `.to_string_lossy()` to safely print paths, \
as they may contain non-Unicode data"
),
message = "`{Self}` doesn't implement `{Display}`",
label = "`{Self}` cannot be formatted with the default formatter",
note = "in format strings you may be able to use `{{:?}}` (or {{:#?}} for pretty-print) instead"
)]
#[doc(alias = "{}")]
pub trait DaemonicDisplay {
#[stable(feature = "rust1", since = "1.0.0")]
fn fmt<'buffer>(&self, f: &mut DaemonicFormatter<'buffer>) -> std::fmt::Result;
}
pub trait DaemonicWrite {
fn write_str(&mut self, s: &str) -> std::fmt::Result;
fn write_char(&mut self, c: char) -> std::fmt::Result {
self.write_str(c.encode_utf8(&mut [0; 4]))
}
fn write_fmt(&mut self, args: DaemonicArguments<'_>) -> std::fmt::Result {
trait SpecWriteFmt {
fn spec_write_fmt(self, args: DaemonicArguments<'_>) -> std::fmt::Result;
}
impl<W: DaemonicWrite + ?Sized> SpecWriteFmt for &mut W {
#[inline]
default fn spec_write_fmt(mut self, args: DaemonicArguments<'_>) -> std::fmt::Result {
daemonic_write(&mut self, args)
}
}
impl<W: DaemonicWrite> SpecWriteFmt for &mut W {
#[inline]
fn spec_write_fmt(self, args: DaemonicArguments<'_>) -> std::fmt::Result {
daemonic_write(self, args)
}
}
self.spec_write_fmt(args)
}
}
pub fn daemonic_write(output: &mut dyn Write, args: DaemonicArguments<'_>) -> std::fmt::Result {
let mut formatter = DaemonicFormatter::new(output, DaemonicFormattingOptions::new());
let mut idx = 0;
match args.fmt {
None => {
for (i, arg) in args.args.iter().enumerate() {
let piece = unsafe { args.pieces.get_unchecked(i) };
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
unsafe {
arg.fmt(&mut formatter)?;
}
idx += 1;
}
}
Some(fmt) => {
for (i, arg) in fmt.iter().enumerate() {
let piece = unsafe { args.pieces.get_unchecked(i) };
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
unsafe { run(&mut formatter, arg, args.args) }?;
idx += 1;
}
}
}
if let Some(piece) = args.pieces.get(idx) {
formatter.buf.write_str(*piece)?;
}
Ok(())
}
#[derive(Copy, Clone)]
pub struct DaemonicArguments<'args> {
pieces: &'args [&'static str],
fmt: Option<&'args [DaemonicPlaceholder]>,
args: &'args [DaemonicArgument<'args>],
}
#[derive(Copy, Clone)]
pub struct DaemonicArgument<'args> {
ty: ArgumentType<'args>,
}
#[derive(Copy, Clone)]
enum ArgumentType<'a> {
Placeholder {
value: NonNull<()>,
formatter: unsafe fn(NonNull<()>, &mut DaemonicFormatter<'_>) -> std::fmt::Result,
_lifetime: PhantomData<&'a ()>,
},
Count(u16),
}
#[derive(Copy, Clone)]
pub struct DaemonicPlaceholder {
pub position: usize,
pub flags: u32,
pub precision: Count,
pub width: Count,
}
#[doc(hidden)]
impl<'args> DaemonicArguments<'args> {
#[inline]
pub fn estimated_capacity(&self) -> usize {
let pieces_length: usize = self.pieces.iter().map(|x| x.len()).sum();
if self.args.is_empty() {
pieces_length
} else if !self.pieces.is_empty() && self.pieces[0].is_empty() && pieces_length < 16 {
0
} else {
pieces_length.checked_mul(2).unwrap_or(0)
}
}
#[must_use]
#[inline]
pub const fn as_str(&self) -> Option<&'static str> {
match (self.pieces, self.args) {
([], []) => Some(""),
([s], []) => Some(s),
_ => None,
}
}
}
impl ! Send for DaemonicArguments<'_> {}
impl ! Sync for DaemonicArguments<'_> {}
impl Debug for DaemonicArguments<'_> {
fn fmt(&self, fmt: &mut DaemonicFormatter<'_>) -> std::fmt::Result {
DaemonicDisplay::fmt(self, fmt)
}
}
impl DaemonicDisplay for DaemonicArguments<'_> {
fn fmt(&self, fmt: &mut DaemonicFormatter<'_>) -> std::fmt::Result {
fn write(output: &mut dyn DaemonicWrite, args: DaemonicArguments<'_>) -> std::fmt::Result {
let mut formatter = DaemonicFormatter::new(output, DaemonicFormattingOptions::new());
let mut idx = 0;
match args.fmt {
None => {
for (i, arg) in args.args.iter().enumerate() {
let piece = unsafe { args.pieces.get_unchecked(i) };
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
unsafe {
arg.fmt(&mut formatter)?;
}
idx += 1;
}
}
Some(fmt) => {
for (i, arg) in fmt.iter().enumerate() {
let piece = unsafe { args.pieces.get_unchecked(i) };
if !piece.is_empty() {
formatter.buf.write_str(*piece)?;
}
unsafe { run(&mut formatter, arg, args.args) }?;
idx += 1;
}
}
}
if let Some(piece) = args.pieces.get(idx) {
formatter.buf.write_str(*piece)?;
}
Ok(())
}
write(fmt.buf, *self)
}
}
unsafe fn run(fmt: &mut DaemonicFormatter<'_>, arg: &DaemonicPlaceholder, args: &[DaemonicArgument<'_>]) -> std::fmt::Result {
let (width, precision) =
unsafe { (getcount(args, &arg.width), getcount(args, &arg.precision)) };
let options = DaemonicFormattingOptions { flags: arg.flags, width, precision };
debug_assert!(arg.position < args.len());
let value = unsafe { args.get_unchecked(arg.position) };
fmt.options = options;
unsafe { value.fmt(fmt) }
}
unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> u16 {
match *cnt {
Count::Is(n) => n,
Count::Implied => 0,
Count::Param(i) => {
debug_assert!(i < args.len());
unsafe { args.get_unchecked(i).as_u16().unwrap_unchecked() }
}
}
}
impl<WRITE: DaemonicWrite + ?Sized> DaemonicWrite for &mut WRITE {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
(**self).write_str(s)
}
fn write_char(&mut self, c: char) -> std::fmt::Result {
(**self).write_char(c)
}
fn write_fmt(&mut self, args: DaemonicArguments<'_>) -> std::fmt::Result {
(**self).write_fmt(args)
}
}
#[allow(missing_debug_implementations)]
pub struct DaemonicFormatter<'buffer> {
options: DaemonicFormattingOptions,
buf: &'buffer mut (dyn DaemonicWrite + 'buffer),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DaemonicFormattingOptions {
flags: u32,
width: u16,
precision: u16,
}
impl DaemonicFormattingOptions {
pub const fn new() -> Self {
Self {
flags: ' ' as u32 | flags::ALIGN_UNKNOWN | flags::ALWAYS_SET,
width: 0,
precision: 0,
}
}
pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self {
let sign = match sign {
None => 0,
Some(Sign::Plus) => flags::SIGN_PLUS_FLAG,
Some(Sign::Minus) => flags::SIGN_MINUS_FLAG,
};
self.flags = self.flags & !(flags::SIGN_PLUS_FLAG | flags::SIGN_MINUS_FLAG) | sign;
self
}
pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self {
if sign_aware_zero_pad {
self.flags |= flags::SIGN_AWARE_ZERO_PAD_FLAG;
} else {
self.flags &= !flags::SIGN_AWARE_ZERO_PAD_FLAG;
}
self
}
pub fn alternate(&mut self, alternate: bool) -> &mut Self {
if alternate {
self.flags |= flags::ALTERNATE_FLAG;
} else {
self.flags &= !flags::ALTERNATE_FLAG;
}
self
}
pub fn fill(&mut self, fill: char) -> &mut Self {
self.flags = self.flags & (u32::MAX << 21) | fill as u32;
self
}
pub fn align(&mut self, align: Option<Alignment>) -> &mut Self {
let align: u32 = match align {
Some(Alignment::Left) => flags::ALIGN_LEFT,
Some(Alignment::Right) => flags::ALIGN_RIGHT,
Some(Alignment::Center) => flags::ALIGN_CENTER,
None => flags::ALIGN_UNKNOWN,
};
self.flags = self.flags & !flags::ALIGN_BITS | align;
self
}
pub fn width(&mut self, width: Option<u16>) -> &mut Self {
if let Some(width) = width {
self.flags |= flags::WIDTH_FLAG;
self.width = width;
} else {
self.flags &= !flags::WIDTH_FLAG;
self.width = 0;
}
self
}
pub fn precision(&mut self, precision: Option<u16>) -> &mut Self {
if let Some(precision) = precision {
self.flags |= flags::PRECISION_FLAG;
self.precision = precision;
} else {
self.flags &= !flags::PRECISION_FLAG;
self.precision = 0;
}
self
}
pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self {
let debug_as_hex = match debug_as_hex {
None => 0,
Some(DebugAsHex::Lower) => flags::DEBUG_LOWER_HEX_FLAG,
Some(DebugAsHex::Upper) => flags::DEBUG_UPPER_HEX_FLAG,
};
self.flags = self.flags & !(flags::DEBUG_LOWER_HEX_FLAG | flags::DEBUG_UPPER_HEX_FLAG)
| debug_as_hex;
self
}
pub const fn get_sign(&self) -> Option<Sign> {
if self.flags & flags::SIGN_PLUS_FLAG != 0 {
Some(Sign::Plus)
} else if self.flags & flags::SIGN_MINUS_FLAG != 0 {
Some(Sign::Minus)
} else {
None
}
}
pub const fn get_sign_aware_zero_pad(&self) -> bool {
self.flags & flags::SIGN_AWARE_ZERO_PAD_FLAG != 0
}
pub const fn get_alternate(&self) -> bool {
self.flags & flags::ALTERNATE_FLAG != 0
}
pub const fn get_fill(&self) -> char {
unsafe { char::from_u32_unchecked(self.flags & 0x1FFFFF) }
}
pub const fn get_align(&self) -> Option<Alignment> {
match self.flags & flags::ALIGN_BITS {
flags::ALIGN_LEFT => Some(Alignment::Left),
flags::ALIGN_RIGHT => Some(Alignment::Right),
flags::ALIGN_CENTER => Some(Alignment::Center),
_ => None,
}
}
pub const fn get_width(&self) -> Option<u16> {
if self.flags & flags::WIDTH_FLAG != 0 { Some(self.width) } else { None }
}
pub const fn get_precision(&self) -> Option<u16> {
if self.flags & flags::PRECISION_FLAG != 0 { Some(self.precision) } else { None }
}
pub const fn get_debug_as_hex(&self) -> Option<DebugAsHex> {
if self.flags & flags::DEBUG_LOWER_HEX_FLAG != 0 {
Some(DebugAsHex::Lower)
} else if self.flags & flags::DEBUG_UPPER_HEX_FLAG != 0 {
Some(DebugAsHex::Upper)
} else {
None
}
}
pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> DaemonicFormatter<'a> {
DaemonicFormatter { options: self, buf: write }
}
}
impl Default for DaemonicFormattingOptions {
fn default() -> Self {
Self::new()
}
}
impl<'a> DaemonicFormatter<'a> {
pub fn new(write: &'a mut (dyn DaemonicWrite + 'a), options: DaemonicFormattingOptions) -> Self {
DaemonicFormatter { options, buf: write }
}
pub fn with_options(&mut self, options: DaemonicFormattingOptions) -> DaemonicFormatter {
DaemonicFormatter { options, buf: self.buf }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Alignment {
Left,
Right,
Center,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
Plus,
Minus,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugAsHex {
Lower,
Upper,
}
mod flags {
pub(super) const SIGN_PLUS_FLAG: u32 = 1 << 21;
pub(super) const SIGN_MINUS_FLAG: u32 = 1 << 22;
pub(super) const ALTERNATE_FLAG: u32 = 1 << 23;
pub(super) const SIGN_AWARE_ZERO_PAD_FLAG: u32 = 1 << 24;
pub(super) const DEBUG_LOWER_HEX_FLAG: u32 = 1 << 25;
pub(super) const DEBUG_UPPER_HEX_FLAG: u32 = 1 << 26;
pub(super) const WIDTH_FLAG: u32 = 1 << 27;
pub(super) const PRECISION_FLAG: u32 = 1 << 28;
pub(super) const ALIGN_BITS: u32 = 0b11 << 29;
pub(super) const ALIGN_LEFT: u32 = 0 << 29;
pub(super) const ALIGN_RIGHT: u32 = 1 << 29;
pub(super) const ALIGN_CENTER: u32 = 2 << 29;
pub(super) const ALIGN_UNKNOWN: u32 = 3 << 29;
pub(super) const ALWAYS_SET: u32 = 1 << 31;
}
macro_rules! argument_new {
($t:ty, $x:expr, $f:expr) => {
DaemonicArgument {
ty: ArgumentType::Placeholder {
value: NonNull::<$t>::from_ref($x).cast(),
#[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
formatter: {
let f: fn(&$t, &mut DaemonicFormatter<'_>) -> Result = $f;
unsafe { core::mem::transmute(f) }
},
#[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
formatter: |ptr: NonNull<()>, fmt: &mut DaemonicFormatter<'_>| {
let func = $f;
let r = unsafe { ptr.cast::<$t>().as_ref() };
(func)(r, fmt)
},
_lifetime: PhantomData,
},
}
};
}
impl<FORMAT, PARTIAL> DaemonicArgument<'_> {
#[inline]
pub const fn new_display<T: DaemonicDisplay, E: DaemonicError<FORMAT, PARTIAL>>(x: &T) -> DaemonicArgument<'_> {
DaemonicArgument {
ty: ArgumentType::Placeholder {
value: NonNull::<T>::from_ref(x).cast(),
#[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
formatter: {
let f: fn(&T, &mut DaemonicFormatter<'_>) -> std::result::Result<T, E> = <T as DaemonicDisplay>::fmt;
unsafe { core::mem::transmute(f) }
},
#[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
formatter: |ptr: NonNull<()>, fmt: &mut DaemonicFormatter<'_>| {
let func = <T as DaemonicDisplay>::fmt;
let r = unsafe { ptr.cast::<T>().as_ref() };
(func)(r, fmt)
},
_lifetime: PhantomData,
},
}
}
#[inline]
pub const fn new_debug<T: DaemonicDebug<FORMAT, PARTIAL>>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicDebug<FORMAT,PARTIAL>>::fmt)
}
#[inline]
pub const fn new_debug_noop<T: DaemonicDebug<FORMAT, PARTIAL>>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, |_: &T, _| Ok(()))
}
#[inline]
pub const fn new_octal<T: DaemonicOctal>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicOctal>::fmt)
}
#[inline]
pub const fn new_lower_hex<T: DaemonicLowerHex>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicLowerHex>::fmt)
}
#[inline]
pub const fn new_upper_hex<T: DaemonicUpperHex>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicUpperHex>::fmt)
}
#[inline]
pub const fn new_pointer<T: DaemonicPointer>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicPointer>::fmt)
}
#[inline]
pub const fn new_binary<T: Binary>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicBinary>::fmt)
}
#[inline]
pub const fn new_lower_exp<T: DaemonicLowerExp>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicLowerExp>::fmt)
}
#[inline]
pub const fn new_upper_exp<T: DaemonicUpperExp>(x: &T) -> DaemonicArgument<'_> {
argument_new!(T, x, <T as DaemonicUpperExp>::fmt)
}
#[inline]
#[track_caller]
pub const fn from_usize(x: &usize) -> DaemonicArgument<'_> {
if *x > u16::MAX as usize {
panic!("Formatting argument out of range");
}
DaemonicArgument { ty: ArgumentType::Count(*x as u16) }
}
#[inline]
pub(super) unsafe fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result {
match self.ty {
ArgumentType::Placeholder { formatter, value, .. } => unsafe { formatter(value, f) },
ArgumentType::Count(_) => unsafe { unreachable_unchecked() },
}
}
#[inline]
pub(super) const fn as_u16(&self) -> Option<u16> {
match self.ty {
ArgumentType::Count(count) => Some(count),
ArgumentType::Placeholder { .. } => None,
}
}
#[inline]
pub const fn none() -> [Self; 0] {
[]
}
}
#[doc(hidden)]
impl<'a> DaemonicArguments<'a> {
#[inline]
pub const fn new_const<const N: usize>(pieces: &'a [&'static str; N]) -> Self {
const { assert!(N <= 1) };
DaemonicArguments { pieces, fmt: None, args: &[] }
}
#[inline]
pub fn new_v1<const P: usize, const A: usize>(
pieces: &'a [&'static str; P],
args: &'a [rt::Argument<'a>; A],
) -> DaemonicArguments<'a> {
const { assert!(P >= A && P <= A + 1, "invalid args") }
DaemonicArguments { pieces, fmt: None, args }
}
#[inline]
pub fn new_v1_formatted(
pieces: &'a [&'static str],
args: &'a [DaemonicArgument<'a>],
fmt: &'a [DaemonicPlaceholder],
_unsafe_arg: DaemonicUnsafeArg,
) -> DaemonicArguments<'a> {
DaemonicArguments { pieces, fmt: Some(fmt), args }
}
}
pub struct DaemonicUnsafeArg {
_private: (),
}
impl DaemonicUnsafeArg {
#[inline]
pub const unsafe fn new() -> Self {
Self { _private: () }
}
}
pub trait DaemonicOctal {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait Binary {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait DaemonicLowerHex {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait DaemonicUpperHex {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait DaemonicPointer {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait DaemonicLowerExp {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
pub trait DaemonicUpperExp {
fn fmt(&self, f: &mut DaemonicFormatter<'_>) -> std::fmt::Result;
}
mod non_null {
use std::mem::MaybeUninit;
use std::num::NonZero;
use std::{intrinsics, mem, ptr};
use std::cmp::Ordering;
use std::hash::Hash;
use std::marker::Unsize;
use std::ops::{CoerceUnsized, DispatchFromDyn};
use std::pin::PinCoerceUnsized;
use std::slice::SliceIndex;
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonNull<T: ?Sized> {
pointer: *const T,
}
impl<T: ?Sized> ! Send for NonNull<T> {}
impl<T: ?Sized> ! Sync for NonNull<T> {}
impl<T: Sized> NonNull<T> {
#[must_use]
#[inline]
pub const fn without_provenance(addr: NonZero<usize>) -> Self {
let pointer = std::ptr::without_provenance(addr.get());
unsafe { NonNull { pointer } }
}
#[must_use]
#[inline]
pub const fn dangling() -> Self {
let align = crate::ptr::Alignment::of::<T>();
NonNull::without_provenance(align.as_nonzero())
}
#[inline]
pub fn with_exposed_provenance(addr: NonZero<usize>) -> Self {
unsafe {
let ptr = crate::ptr::with_exposed_provenance_mut(addr.get());
NonNull::new_unchecked(ptr)
}
}
#[inline]
#[must_use]
pub const unsafe fn as_uninit_ref<'a>(self) -> &'a MaybeUninit<T> {
unsafe { &*self.cast().as_ptr() }
}
#[inline]
#[must_use]
pub const unsafe fn as_uninit_mut<'a>(self) -> &'a mut MaybeUninit<T> {
unsafe { &mut *self.cast().as_ptr() }
}
}
impl<T: ?Sized> NonNull<T> {
#[inline]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
unsafe {
assert_unsafe_precondition!(
check_language_ub,
"NonNull::new_unchecked requires that the pointer is non-null",
(ptr: *mut () = ptr as *mut ()) => !ptr.is_null()
);
NonNull { pointer: ptr as _ }
}
}
#[inline]
pub const fn new(ptr: *mut T) -> Option<Self> {
if !ptr.is_null() {
Some(unsafe { Self::new_unchecked(ptr) })
} else {
None
}
}
#[inline]
pub const fn from_ref(r: &T) -> Self {
unsafe { NonNull { pointer: r as *const T } }
}
#[inline]
pub const fn from_mut(r: &mut T) -> Self {
unsafe { NonNull { pointer: r as *mut T } }
}
#[inline]
pub const fn from_raw_parts(
data_pointer: NonNull<impl super::Thin>,
metadata: <T as super::Pointee>::Metadata,
) -> NonNull<T> {
unsafe {
NonNull::new_unchecked(super::from_raw_parts_mut(data_pointer.as_ptr(), metadata))
}
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_raw_parts(self) -> (NonNull<()>, <T as super::Pointee>::Metadata) {
(self.cast(), super::metadata(self.as_ptr()))
}
#[must_use]
#[inline]
pub fn addr(self) -> NonZero<usize> {
unsafe { NonZero::new_unchecked(self.as_ptr().addr()) }
}
pub fn expose_provenance(self) -> NonZero<usize> {
unsafe { NonZero::new_unchecked(self.as_ptr().expose_provenance()) }
}
#[must_use]
#[inline]
pub fn with_addr(self, addr: NonZero<usize>) -> Self {
unsafe { NonNull::new_unchecked(self.as_ptr().with_addr(addr.get()) as *mut _) }
}
#[must_use]
#[inline]
pub fn map_addr(self, f: impl FnOnce(NonZero<usize>) -> NonZero<usize>) -> Self {
self.with_addr(f(self.addr()))
}
#[rustc_never_returns_null_ptr]
#[must_use]
#[inline(always)]
pub const fn as_ptr(self) -> *mut T {
unsafe { mem::transmute::<Self, *mut T>(self) }
}
#[must_use]
#[inline(always)]
pub const unsafe fn as_ref<'a>(&self) -> &'a T {
unsafe { &*self.as_ptr().cast_const() }
}
#[must_use]
#[inline(always)]
pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
unsafe { &mut *self.as_ptr() }
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn cast<U>(self) -> NonNull<U> {
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] #[must_use = "returns a new pointer rather than modifying its argument"]
pub const unsafe fn offset(self, count: isize) -> Self
where
T: Sized,
{
unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
}
#[must_use]
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn byte_offset(self, count: isize) -> Self {
unsafe { NonNull { pointer: self.as_ptr().byte_offset(count) } }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] #[must_use = "returns a new pointer rather than modifying its argument"]
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
{
unsafe { NonNull { pointer: intrinsics::offset(self.as_ptr(), count) } }
}
#[must_use]
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn byte_add(self, count: usize) -> Self {
unsafe { NonNull { pointer: self.as_ptr().byte_add(count) } }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] #[must_use = "returns a new pointer rather than modifying its argument"]
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
if T::IS_ZST {
self
} else {
unsafe { self.offset((count as isize).unchecked_neg()) }
}
}
#[must_use]
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn byte_sub(self, count: usize) -> Self {
unsafe { NonNull { pointer: self.as_ptr().byte_sub(count) } }
}
#[inline]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn offset_from(self, origin: NonNull<T>) -> isize
where
T: Sized,
{
unsafe { self.as_ptr().offset_from(origin.as_ptr()) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: NonNull<U>) -> isize {
unsafe { self.as_ptr().byte_offset_from(origin.as_ptr()) }
}
#[inline]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn offset_from_unsigned(self, subtracted: NonNull<T>) -> usize
where
T: Sized,
{
unsafe { self.as_ptr().offset_from_unsigned(subtracted.as_ptr()) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn byte_offset_from_unsigned<U: ?Sized>(self, origin: NonNull<U>) -> usize {
unsafe { self.as_ptr().byte_offset_from_unsigned(origin.as_ptr()) }
}
#[inline]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn read(self) -> T
where
T: Sized,
{
unsafe { ptr::read(self.as_ptr()) }
}
#[inline]
#[cfg_attr(
miri,
track_caller
)] pub unsafe fn read_volatile(self) -> T
where
T: Sized,
{
unsafe { ptr::read_volatile(self.as_ptr()) }
}
#[inline]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn read_unaligned(self) -> T
where
T: Sized,
{
unsafe { ptr::read_unaligned(self.as_ptr()) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize)
where
T: Sized,
{
unsafe { ptr::copy(self.as_ptr(), dest.as_ptr(), count) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize)
where
T: Sized,
{
unsafe { ptr::copy_nonoverlapping(self.as_ptr(), dest.as_ptr(), count) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize)
where
T: Sized,
{
unsafe { ptr::copy(src.as_ptr(), self.as_ptr(), count) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize)
where
T: Sized,
{
unsafe { ptr::copy_nonoverlapping(src.as_ptr(), self.as_ptr(), count) }
}
#[inline(always)]
pub unsafe fn drop_in_place(self) {
unsafe { ptr::drop_in_place(self.as_ptr()) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn write(self, val: T)
where
T: Sized,
{
unsafe { ptr::write(self.as_ptr(), val) }
}
#[inline(always)]
#[doc(alias = "memset")]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn write_bytes(self, val: u8, count: usize)
where
T: Sized,
{
unsafe { ptr::write_bytes(self.as_ptr(), val, count) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub unsafe fn write_volatile(self, val: T)
where
T: Sized,
{
unsafe { ptr::write_volatile(self.as_ptr(), val) }
}
#[inline(always)]
#[cfg_attr(
miri,
track_caller
)] pub const unsafe fn write_unaligned(self, val: T)
where
T: Sized,
{
unsafe { ptr::write_unaligned(self.as_ptr(), val) }
}
#[inline(always)]
pub const unsafe fn replace(self, src: T) -> T
where
T: Sized,
{
unsafe { ptr::replace(self.as_ptr(), src) }
}
#[inline(always)]
pub const unsafe fn swap(self, with: NonNull<T>)
where
T: Sized,
{
unsafe { ptr::swap(self.as_ptr(), with.as_ptr()) }
}
#[inline]
#[must_use]
pub fn align_offset(self, align: usize) -> usize
where
T: Sized,
{
if !align.is_power_of_two() {
core::panic!("align_offset: align is not a power-of-two");
}
{
unsafe { ptr::align_offset(self.as_ptr(), align) }
}
}
#[inline]
#[must_use]
pub fn is_aligned(self) -> bool
where
T: Sized,
{
self.as_ptr().is_aligned()
}
#[inline]
#[must_use]
pub fn is_aligned_to(self, align: usize) -> bool {
self.as_ptr().is_aligned_to(align)
}
}
impl<T> NonNull<[T]> {
#[must_use]
#[inline]
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
unsafe { Self::new_unchecked(super::slice_from_raw_parts_mut(data.as_ptr(), len)) }
}
#[must_use]
#[inline]
pub const fn len(self) -> usize {
self.as_ptr().len()
}
#[must_use]
#[inline]
pub const fn is_empty(self) -> bool {
self.len() == 0
}
#[inline]
#[must_use]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.cast()
}
#[inline]
#[must_use]
#[rustc_never_returns_null_ptr]
pub const fn as_mut_ptr(self) -> *mut T {
self.as_non_null_ptr().as_ptr()
}
#[inline]
#[must_use]
pub const unsafe fn as_uninit_slice<'a>(self) -> &'a [MaybeUninit<T>] {
unsafe { slice::from_raw_parts(self.cast().as_ptr(), self.len()) }
}
#[inline]
#[must_use]
pub const unsafe fn as_uninit_slice_mut<'a>(self) -> &'a mut [MaybeUninit<T>] {
unsafe { slice::from_raw_parts_mut(self.cast().as_ptr(), self.len()) }
}
#[inline]
pub unsafe fn get_unchecked_mut<I>(self, index: I) -> NonNull<I::Output>
where
I: SliceIndex<[T]>,
{
unsafe { NonNull::new_unchecked(self.as_ptr().get_unchecked_mut(index)) }
}
}
impl<T: ?Sized> Clone for NonNull<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for NonNull<T> {}
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T>
where
T: Unsize<U>,
{}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T>
where
T: Unsize<U>,
{}
unsafe impl<T: ?Sized> PinCoerceUnsized for NonNull<T> {}
impl<T> core::marker::PointerLike for NonNull<T> {}
impl<T: ?Sized> fmt::Debug for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
impl<T: ?Sized> fmt::Pointer for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
impl<T: ?Sized> Eq for NonNull<T> {}
impl<T: ?Sized> PartialEq for NonNull<T> {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
fn eq(&self, other: &Self) -> bool {
self.as_ptr() == other.as_ptr()
}
}
impl<T: ?Sized> Ord for NonNull<T> {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
fn cmp(&self, other: &Self) -> Ordering {
self.as_ptr().cmp(&other.as_ptr())
}
}
impl<T: ?Sized> PartialOrd for NonNull<T> {
#[inline]
#[allow(ambiguous_wide_pointer_comparisons)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ptr().partial_cmp(&other.as_ptr())
}
}
impl<T: ?Sized> hash::Hash for NonNull<T> {
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.as_ptr().hash(state)
}
}
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
#[inline]
fn from(unique: Unique<T>) -> Self {
unique.as_non_null_ptr()
}
}
impl<T: ?Sized> From<&mut T> for NonNull<T> {
#[inline]
fn from(r: &mut T) -> Self {
NonNull::from_mut(r)
}
}
impl<T: ?Sized> From<&T> for NonNull<T> {
#[inline]
fn from(r: &T) -> Self {
NonNull::from_ref(r)
}
}
use crate::fmt;
use crate::marker::{PhantomData, Unsize};
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::pin::PinCoerceUnsized;
use crate::ptr::NonNull;
#[doc(hidden)]
#[repr(transparent)]
pub struct Unique<T: ?Sized> {
pointer: NonNull<T>,
_marker: PhantomData<T>,
}
unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
impl<T: Sized> Unique<T> {
#[must_use]
#[inline]
pub const fn dangling() -> Self {
Unique { pointer: NonNull::dangling(), _marker: PhantomData }
}
}
impl<T: ?Sized> Unique<T> {
#[inline]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
unsafe { Unique { pointer: NonNull::new_unchecked(ptr), _marker: PhantomData } }
}
#[inline]
pub const fn new(ptr: *mut T) -> Option<Self> {
if let Some(pointer) = NonNull::new(ptr) {
Some(Unique { pointer, _marker: PhantomData })
} else {
None
}
}
#[inline]
pub const fn from_non_null(pointer: NonNull<T>) -> Self {
Unique { pointer, _marker: PhantomData }
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub const fn as_ptr(self) -> *mut T {
self.pointer.as_ptr()
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub const fn as_non_null_ptr(self) -> NonNull<T> {
self.pointer
}
#[must_use]
#[inline]
pub const unsafe fn as_ref(&self) -> &T {
unsafe { self.pointer.as_ref() }
}
#[must_use]
#[inline]
pub const unsafe fn as_mut(&mut self) -> &mut T {
unsafe { self.pointer.as_mut() }
}
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub const fn cast<U>(self) -> Unique<U> {
Unique { pointer: self.pointer.cast(), _marker: PhantomData }
}
}
impl<T: ?Sized> Clone for Unique<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Unique<T> {}
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T>
where
T: Unsize<U>,
{}
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T>
where
T: Unsize<U>,
{}
unsafe impl<T: ?Sized> PinCoerceUnsized for Unique<T> {}
impl<T: ?Sized> fmt::Debug for Unique<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
impl<T: ?Sized> fmt::Pointer for Unique<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
impl<T: ?Sized> From<&mut T> for Unique<T> {
#[inline]
fn from(reference: &mut T) -> Self {
Self::from(NonNull::from(reference))
}
}
impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
#[inline]
fn from(pointer: NonNull<T>) -> Self {
Unique::from_non_null(pointer)
}
}
}
}
mod error {
pub use crate::DaemonicError;
}
}
}
pub(crate) mod daemonic_contract {
use crate::DaemonicError;
use crate::Position;
use crate::SeverityType;
pub(crate) use daemonic_result::DiagnosticLevel;
pub trait DaemonicContract<FORMAT, PARTIAL>: Sized + Send + Sync {
#[cfg(feature = "DaemonicCompiler")]
type Input: DaemonicBinary<FORMAT, PARTIAL>;
#[cfg(not(feature = "DaemonicCompiler"))]
type Input;
type Output: IntoDaemonicResult<FORMAT, PARTIAL>;
#[cfg(feature = "DaemonicCompiler")]
type Topology: Send + Sync;
#[cfg(feature = "DaemonicCompiler")]
type Integrity: Send + Sync;
#[cfg(not(feature = "DaemonicCompiler"))]
type Topology;
#[cfg(not(feature = "DaemonicCompiler"))]
type Integrity;
type Error: for<'error> DaemonicError<'error, FORMAT, PARTIAL>;
fn position(&self) -> Position;
#[must_use]
fn execute(
input: Self::Input,
) -> Self::Output;
}
pub(crate) trait IntoDaemonicResult<FORMAT, PARTIAL> {
#[must_use]
type Success = FORMAT;
#[must_use]
type Error: for<'error> DaemonicError<'error, FORMAT, PARTIAL>;
type Partial = Option<PARTIAL>;
#[must_use]
fn into_result(self) -> DaemonicResult<Self::Success, Self::Error>;
fn into_partial(self) -> DaemonicResult<PARTIAL, Self::Error>;
}
pub enum DaemonicResult<OUTPUT, ERROR, S = ()>
where
ERROR: for<'error> DaemonicError<'error, FORMAT, PARTIAL>,
{
Success(OUTPUT),
Failure(ERROR),
Partial {
salvaged: S,
errors: Option<Vec<ERROR>>,
},
}
impl<OUTPUT, FORMAT, PARTIAL, ERROR> DaemonicResult<OUTPUT, ERROR>
where
ERROR: for<'error> DaemonicError<'error, FORMAT, PARTIAL>,
{
pub fn is_success(&self) -> bool {
matches!(self, Self::Success(_))
}
pub fn is_failure(&self) -> bool {
matches!(self, Self::Failure(_))
}
pub fn is_partial(&self) -> bool {
matches!(self, Self::Partial { .. })
}
pub fn into_result(self) -> Result<OUTPUT, ERROR> {
match self {
Self::Success(o) => Ok(o),
Self::Failure(e) => Err(e),
Self::Partial { errors, .. } => {
Err(errors
.and_then(|v| v.into_iter().next())
.expect("partial must have errors"))
}
}
}
pub fn map<U, S>(self, f: impl FnOnce(OUTPUT) -> U) -> DaemonicResult<U, ERROR, S> {
match self {
Self::Success(o) => DaemonicResult::Success(f(o)),
Self::Failure(e) => DaemonicResult::Failure(e),
Self::Partial { salvaged, errors } => {
DaemonicResult::Partial { salvaged, errors }
}
}
}
}
pub(crate) trait DaemonicBinary<FORMAT, PARTIAL>: Sized + Send + Sync {
type Error: for<'error> DaemonicError<'error, FORMAT, PARTIAL>;
#[must_use]
fn build<OUTPUT: DaemonicBinary<FORMAT, PARTIAL>, SRCSYMBOL, ERROR: for<'error> DaemonicError<'error, FORMAT, PARTIAL>>(input: SRCSYMBOL) -> DaemonicResult<OUTPUT, ERROR>;
#[must_use]
fn try_deconstruct<DECONSYMBOL>(self) -> DaemonicResult<DECONSYMBOL, Self::Error, Self>;
fn inspect<INSPECTION>(&self) -> INSPECTION;
fn revalidate(&mut self) -> DaemonicResult<(), Self::Error, ()>;
fn verify_integrity(&self) -> bool;
fn glass_state(&self) -> SeverityType;
fn evolution_state<EVOLUTION>(&self) -> &EVOLUTION;
}
impl<TOPOLOGY: Send + Sync, INTEGRITY: Send + Sync> Partial for PartialBinary<'_, TOPOLOGY, INTEGRITY> {
fn salvage_ratio(&self) -> f64 {
let mut count = 0.0;
let mut total = 3.0;
if self.topology.is_some() {
count += 1.0;
}
if self.integrity.is_some() {
count += 1.0;
}
if self.checksum.is_some() {
count += 1.0;
}
count / total
}
}
pub struct PartialBinary<'position, TOPOLOGY: Send + Sync, INTEGRITY: Send + Sync> {
pub topology: Option<TOPOLOGY>,
pub integrity: Option<INTEGRITY>,
pub checksum: Option<u64>,
pub failed_at: Position<'position>,
pub failure_reason: String,
}
pub(crate) trait Partial: Send + Sync {
fn salvage_ratio(&self) -> f64;
}
pub(crate) mod daemonic_result {
pub(crate) mod mirror_chemistry {
use crate::{GlassState, SeverityType};
use bonding::*;
use elements::*;
use stability::*;
use std::time::Duration;
use table::{compounds::*, *};
use crate::daemonic::daemonic_contract::daemonic_result::severity_types::{GlassFracture, GlassHelp, GlassNote, GlassShattered, GlassStable, GlassSuggestion, GlassWarp};
pub(crate) mod elements {
use super::super::severity_types::Severity::*;
use super::*;
pub const SPECULAR: ReflectionProperties = ReflectionProperties {
fidelity: Fidelity::Specular,
temporality: Temporality::Instantaneous,
spatiality: Spatiality::Identity,
selectivity: Selectivity::Complete,
energy_cost: EnergyCost::Minimal,
};
pub const ABSORPTIVE: ReflectionProperties = ReflectionProperties {
fidelity: Fidelity::Absorptive,
temporality: Temporality::None,
spatiality: Spatiality::Collapsed,
selectivity: Selectivity::None,
energy_cost: EnergyCost::Sustained(f64::MAX),
};
pub fn delayed(offset: Duration) -> ReflectionProperties {
ReflectionProperties {
fidelity: Fidelity::Specular,
temporality: Temporality::Delayed(offset),
spatiality: Spatiality::Inverted,
selectivity: Selectivity::Complete,
energy_cost: EnergyCost::Finite(offset.as_secs_f64()),
}
}
pub const INVERTED: ReflectionProperties = ReflectionProperties {
fidelity: Fidelity::Specular,
temporality: Temporality::Instantaneous,
spatiality: Spatiality::Inverted,
selectivity: Selectivity::Complete,
energy_cost: EnergyCost::Minimal,
};
pub fn transformative(
transform: SpatialTransform,
reversible: bool,
) -> ReflectionProperties {
ReflectionProperties {
fidelity: if reversible {
Fidelity::Specular
} else {
Fidelity::Lossy(0.5)
},
temporality: Temporality::Instantaneous,
spatiality: Spatiality::Transformed(transform),
selectivity: Selectivity::Complete,
energy_cost: EnergyCost::Finite(1.0), }
}
pub fn selective(properties: Vec<PropertyId>) -> ReflectionProperties {
ReflectionProperties {
fidelity: Fidelity::Specular, temporality: Temporality::Instantaneous,
spatiality: Spatiality::Inverted,
#[allow(unused_doc_comments)]
selectivity: Selectivity::Partial(properties.clone()),
energy_cost: EnergyCost::Finite(properties.len() as f64 * 0.1),
}
}
pub fn prophetic(required_walks: u64) -> ReflectionProperties {
ReflectionProperties {
fidelity: Fidelity::Specular, temporality: Temporality::Prophetic {
requires_prior_walks: required_walks,
},
spatiality: Spatiality::Inverted,
selectivity: Selectivity::Complete,
energy_cost: EnergyCost::Unbounded, }
}
}
pub(crate) mod bonding {
use super::*;
#[derive(Debug)]
pub enum BondResult {
Compound(ReflectionProperties),
Dominated(ReflectionProperties),
Contradiction,
Unstable(ReflectionProperties, Duration),
}
pub fn combine(
a: &ReflectionProperties,
b: &ReflectionProperties,
) -> BondResult {
if a.fidelity == Fidelity::Absorptive {
if b.fidelity == Fidelity::Specular {
return BondResult::Contradiction;
}
return BondResult::Dominated(a.clone());
}
if b.fidelity == Fidelity::Absorptive {
if a.fidelity == Fidelity::Specular {
return BondResult::Contradiction;
}
return BondResult::Dominated(b.clone());
}
if *a == super::elements::SPECULAR {
return BondResult::Compound(b.clone());
}
if *b == super::elements::SPECULAR {
return BondResult::Compound(a.clone());
}
if let (Temporality::Delayed(t1), Temporality::Delayed(t2)) =
(&a.temporality, &b.temporality)
{
let mut compound = a.clone();
compound.temporality = Temporality::Delayed(*t1 + *t2);
compound.energy_cost = stack_energy(&a.energy_cost, &b.energy_cost);
return BondResult::Compound(compound);
}
if matches!(a.temporality, Temporality::Prophetic { .. })
|| matches!(b.temporality, Temporality::Prophetic { .. })
{
let mut compound = combine_properties(a, b);
return BondResult::Unstable(compound, Duration::from_millis(100));
}
let combined_selectivity = match (&a.selectivity, &b.selectivity) {
(Selectivity::Complete, s) | (s, Selectivity::Complete) => s.clone(),
(Selectivity::None, _) | (_, Selectivity::None) => Selectivity::None,
(Selectivity::Partial(p1), Selectivity::Partial(p2)) => {
let intersection: Vec<_> =
p1.iter().filter(|x| p2.contains(x)).copied().collect();
if intersection.is_empty() {
Selectivity::None
} else {
Selectivity::Partial(intersection)
}
}
(Selectivity::Single(s1), Selectivity::Single(s2)) => {
if s1 == s2 {
Selectivity::Single(*s1)
} else {
Selectivity::None
}
}
(Selectivity::Single(s), Selectivity::Partial(p))
| (Selectivity::Partial(p), Selectivity::Single(s)) => {
if p.contains(s) {
Selectivity::Single(*s)
} else {
Selectivity::None
}
}
};
let mut compound = combine_properties(a, b);
compound.selectivity = combined_selectivity;
BondResult::Compound(compound)
}
fn combine_properties(
a: &ReflectionProperties,
b: &ReflectionProperties,
) -> ReflectionProperties {
ReflectionProperties {
fidelity: combine_fidelity(&a.fidelity, &b.fidelity),
temporality: combine_temporality(&a.temporality, &b.temporality),
spatiality: combine_spatiality(&a.spatiality, &b.spatiality),
selectivity: Selectivity::Complete, energy_cost: stack_energy(&a.energy_cost, &b.energy_cost),
}
}
fn combine_fidelity(a: &Fidelity, b: &Fidelity) -> Fidelity {
match (a, b) {
(Fidelity::Absorptive, _) | (_, Fidelity::Absorptive) => {
Fidelity::Absorptive
}
(Fidelity::Destructive, _) | (_, Fidelity::Destructive) => {
Fidelity::Destructive
}
(Fidelity::Lossy(x), Fidelity::Lossy(y)) => Fidelity::Lossy(x * y),
(Fidelity::Lossy(x), Fidelity::Specular)
| (Fidelity::Specular, Fidelity::Lossy(x)) => Fidelity::Lossy(*x),
(Fidelity::Specular, Fidelity::Specular) => Fidelity::Specular,
}
}
fn combine_temporality(a: &Temporality, b: &Temporality) -> Temporality {
match (a, b) {
(Temporality::None, _) | (_, Temporality::None) => Temporality::None,
(Temporality::Instantaneous, t) | (t, Temporality::Instantaneous) => {
t.clone()
}
(Temporality::Delayed(t1), Temporality::Delayed(t2)) => {
Temporality::Delayed(*t1 + *t2)
}
_ => Temporality::Variable {
min: Duration::ZERO, max: Duration::from_secs(1), },
}
}
fn combine_spatiality(a: &Spatiality, b: &Spatiality) -> Spatiality {
match (a, b) {
(Spatiality::Collapsed, _) | (_, Spatiality::Collapsed) => {
Spatiality::Collapsed
}
(Spatiality::Identity, s) | (s, Spatiality::Identity) => s.clone(),
(Spatiality::Inverted, Spatiality::Inverted) => Spatiality::Identity, _ => a.clone(), }
}
fn stack_energy(a: &EnergyCost, b: &EnergyCost) -> EnergyCost {
match (a, b) {
(EnergyCost::Unbounded, _) | (_, EnergyCost::Unbounded) => {
EnergyCost::Unbounded
}
(EnergyCost::Minimal, e) | (e, EnergyCost::Minimal) => e.clone(),
(EnergyCost::Finite(x), EnergyCost::Finite(y)) => {
EnergyCost::Finite(x + y)
}
(EnergyCost::Sustained(x), EnergyCost::Sustained(y)) => {
EnergyCost::Sustained(x + y)
}
(EnergyCost::Finite(x), EnergyCost::Sustained(y))
| (EnergyCost::Sustained(y), EnergyCost::Finite(x)) => {
EnergyCost::Sustained(x + y)
}
}
}
}
pub(crate) mod stability {
use super::*;
#[derive(Debug)]
pub enum Stability {
Stable,
Metastable { perturbation_threshold: f64 },
Unstable {
decay_to: Box<ReflectionProperties>,
half_life: Duration,
},
Impossible,
}
pub fn assess(props: &ReflectionProperties) -> Stability {
if *props == super::elements::SPECULAR {
return Stability::Stable;
}
if is_contradictory(props) {
return Stability::Impossible;
}
if matches!(props.temporality, Temporality::Prophetic { .. }) {
return Stability::Unstable {
decay_to: Box::new(super::elements::SPECULAR.clone()),
half_life: Duration::from_millis(50),
};
}
if props.fidelity == Fidelity::Absorptive {
if !matches!(props.energy_cost, EnergyCost::Sustained(_)) {
return Stability::Unstable {
decay_to: Box::new(super::elements::SPECULAR.clone()),
half_life: Duration::from_secs(1),
};
}
return Stability::Metastable {
perturbation_threshold: 0.1,
};
}
match &props.energy_cost {
EnergyCost::Minimal => Stability::Stable,
EnergyCost::Finite(e) if *e < 1.0 => Stability::Stable,
EnergyCost::Finite(e) if *e < 10.0 => Stability::Metastable {
perturbation_threshold: 1.0 / e,
},
EnergyCost::Finite(_) => Stability::Unstable {
decay_to: Box::new(super::elements::SPECULAR.clone()),
half_life: Duration::from_secs(10),
},
EnergyCost::Sustained(e) if *e < 100.0 => Stability::Metastable {
perturbation_threshold: 1.0 / e,
},
EnergyCost::Sustained(_) => Stability::Unstable {
decay_to: Box::new(super::elements::SPECULAR.clone()),
half_life: Duration::from_secs(1),
},
EnergyCost::Unbounded => Stability::Unstable {
decay_to: Box::new(super::elements::SPECULAR.clone()),
half_life: Duration::from_millis(10),
},
}
}
fn is_contradictory(props: &ReflectionProperties) -> bool {
if props.fidelity == Fidelity::Specular
&& props.selectivity == Selectivity::None
{
return true;
}
if props.selectivity == Selectivity::Complete
&& props.fidelity == Fidelity::Absorptive
{
return true;
}
false
}
}
pub(crate) mod table {
use super::*;
pub enum ReflectionGroup {
Noble,
Reactive,
Transitional,
Rare,
Synthetic,
}
pub fn classify(props: &ReflectionProperties) -> ReflectionGroup {
match stability::assess(props) {
stability::Stability::Stable => {
if props.energy_cost == EnergyCost::Minimal {
ReflectionGroup::Noble
} else {
ReflectionGroup::Transitional
}
}
stability::Stability::Metastable { .. } => ReflectionGroup::Reactive,
stability::Stability::Unstable { .. } => {
if matches!(props.temporality, Temporality::Prophetic { .. }) {
ReflectionGroup::Rare
} else {
ReflectionGroup::Transitional
}
}
stability::Stability::Impossible => ReflectionGroup::Synthetic, }
}
pub(crate) mod compounds {
use super::super::*;
pub fn echo(delay: Duration) -> ReflectionProperties {
let specular = elements::SPECULAR.clone();
let delayed = elements::delayed(delay);
match bonding::combine(&specular, &delayed) {
bonding::BondResult::Compound(c) => c,
_ => unreachable!("Echo should always be valid"),
}
}
pub fn filter(properties: Vec<super::PropertyId>) -> ReflectionProperties {
elements::selective(properties)
}
pub fn black_mirror(
hidden: Vec<super::PropertyId>,
visible: Vec<super::PropertyId>,
) -> ReflectionProperties {
ReflectionProperties {
fidelity: super::Fidelity::Lossy(
visible.len() as f64 / (hidden.len() + visible.len()) as f64,
),
temporality: super::Temporality::Instantaneous,
spatiality: super::Spatiality::Inverted,
selectivity: super::Selectivity::Partial(visible),
energy_cost: super::EnergyCost::Sustained(hidden.len() as f64),
}
}
pub fn double_mirror() -> ReflectionProperties {
ReflectionProperties {
fidelity: super::Fidelity::Specular,
temporality: super::Temporality::Instantaneous,
spatiality: super::Spatiality::Identity, selectivity: super::Selectivity::Complete,
energy_cost: super::EnergyCost::Finite(0.1), }
}
}
}
pub trait Reflection {
type Cause: ReflectionCause;
fn properties(&self) -> ReflectionProperties;
}
pub trait ReflectionCause {
fn name<'name>(&self) -> &'name str;
fn recoverable(&self) -> bool;
}
pub trait Reflective {
fn reflect<CAUSE: ReflectionCause>(&self, cause: CAUSE) -> impl Reflection;
}
pub trait ReflectionComposite {
type Cause: ReflectionCause;
fn combine(reflections: &[&dyn Reflection<Cause=Self::Cause>]) -> BondResult;
fn assess_stability(&self) -> Stability;
}
pub trait MirrorType<'mirrortype>: Send + Sync + 'mirrortype {
fn properties(&self) -> ReflectionProperties;
}
pub fn reflections_to_glass<GLASS: for<'state> GlassState<'state>>(
reflections: &[&dyn Reflection<Cause=impl ReflectionCause>], ) -> GLASS {
use bonding::BondResult;
let combined = reflections
.iter()
.map(|r| r.properties()).fold(
elements::SPECULAR,
|acc, props| match bonding::combine(&acc, &props) {
BondResult::Compound(c) => c,
BondResult::Dominated(d) => d,
BondResult::Contradiction => elements::ABSORPTIVE,
BondResult::Unstable(u, _) => u,
},
);
let stability = stability::assess(&combined);
GLASS::from_reflection(combined)
}
impl GlassState for SeverityType {
type Mirror = ();
type Cause = ();
fn from_reflection(props: &ReflectionProperties) -> fn(dyn GlassState<Cause=_, Mirror=_>) {
match &props.fidelity {
Fidelity::Specular => SeverityType::stable(),
Fidelity::Lossy(x) if *x > 0.8 => SeverityType::help(),
Fidelity::Lossy(x) if *x > 0.5 => SeverityType::suggestion(),
Fidelity::Lossy(_) => SeverityType::fracture(&props),
Fidelity::Destructive => SeverityType::warp(&props),
Fidelity::Absorptive => SeverityType::shatter(),
}
}
fn dominance(&self) -> u8 {
0
}
fn stable<'stable>() -> fn(GlassStable) -> SeverityType {
SeverityType::GlassStable
}
fn fracture(props: &ReflectionProperties) -> fn(GlassFracture) -> SeverityType {
SeverityType::GlassFracture
}
fn warp(props: &ReflectionProperties) -> fn(GlassWarp) -> SeverityType {
SeverityType::GlassWarp
}
fn shatter<'shatter>() -> fn(GlassShattered) -> SeverityType {
SeverityType::GlassShattered
}
fn note<'note>() -> fn(GlassNote) -> SeverityType {
SeverityType::GlassNote
}
fn suggestion<'suggestion>() -> fn(GlassSuggestion) -> SeverityType {
SeverityType::GlassSuggestion
}
fn help<'help>() -> fn(GlassHelp) -> SeverityType {
SeverityType::GlassHelp
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ReflectionProperties {
pub fidelity: Fidelity,
pub temporality: Temporality,
pub spatiality: Spatiality,
pub selectivity: Selectivity,
pub energy_cost: EnergyCost,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Fidelity {
Specular,
Lossy(f64), Destructive,
Absorptive,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Temporality {
Instantaneous,
Delayed(Duration),
Variable { min: Duration, max: Duration }, Prophetic { requires_prior_walks: u64 },
None,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Spatiality {
Inverted,
Identity,
Transformed(SpatialTransform),
Collapsed,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Selectivity {
Complete,
Partial(Vec<PropertyId>),
Single(PropertyId),
None,
}
#[derive(Clone, Debug, PartialEq)]
pub enum EnergyCost {
Minimal,
Finite(f64),
Sustained(f64),
Unbounded,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SpatialTransform {
}
pub type PropertyId = u32;
}
pub(crate) mod error_types {
pub(crate) mod error_messages {
use os::OsError;
use daemonic::entity::shade::ShadeError;
use generic::GenericError;
use daemonic::Daemonic;
use super::*;
pub struct EntropyTermination {}
pub(crate) mod os {
}
pub(crate) mod daemonic {
}
pub(crate) mod generic {
}
}
use crate::{
EnumerationRouter,
daemonic::{
daemonic_contract::{
daemonic_result::{
error_types::{
error_messages::{
generic::GenericError,
os::OsError,
daemonic::Daemonic,
}
}
}
}
},
};
pub enum Error {
Generic(GenericError),
#[cfg_attr(feature = "Libc", )]
OS(OsError),
Daemonic(Daemonic),
}
impl EnumerationRouter for Error {}
}
pub(crate) mod diagnostic {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
mod traits {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use super::structures::*;
#[rustc_diagnostic_item = "Diagnostic"]
pub trait Diagnostic<'diagnostic, GUARANTEE: EmissionGuarantee = ErrorGuaranteed> {
#[must_use]
fn into_diag(
self,
dcx: DiagCtxtHandle<'diagnostic>,
level: DiagnosticLevel,
) -> Diag<'diagnostic, GUARANTEE>;
}
#[rustc_diagnostic_item = "LintDiagnostic"]
pub trait LintDiagnostic<'diagnostic, GUARANTEE: EmissionGuarantee> {
fn decorate_lint<'decorate_lint>(self, diag: &'decorate_lint mut Diag<'diagnostic, GUARANTEE>);
}
pub trait EmissionGuarantee: Sized {
type EmitResult = Self;
const CONTINUEABLE: bool = true;
type RecoveryHandler: RecoveryHandler<Self> = NoRecovery;
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult;
fn emit_continuable(diag: Diag<'_, Self>) -> crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome<Self::EmitResult> {
let result = Self::emit_producing_guarantee(diag);
if Self::CONTINUEABLE {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::Continue(result)
} else if let Some(recovered) = Self::RecoveryHandler::attempt_recovery(&result) {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::Recovered(recovered)
} else {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmitOutcome::MustStop(result)
}
}
}
pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>; pub type DiagArgName = Cow<'static, str>;
pub trait IntoDiagArg {
fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue;
}
}
mod structures {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use crate::daemonic::daemonic_contract::daemonic_result::diagnostic::EmissionGuarantee;
#[derive(
Clone,
Copy,
Debug,
Hash,
PartialEq,
Eq,
PartialOrd,
Ord
)] pub struct ErrorGuaranteed(());
pub struct FatalErrorMarker;
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct FatalError;
pub struct FatalRecovery;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DiagArgValue {
Str(Cow<'static, str>),
Number(i32),
StrListSepByAnd(Vec<Cow<'static, str>>),
}
#[must_use]
pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> {
pub dcx: DiagnosticContextHandle<'a>,
pub(crate) diag: Option<Box<DiagInner>>,
pub(crate) _marker: PhantomData<G>,
}
#[must_use]
#[derive(Clone, Debug)]
pub struct DiagInner {
pub level: crate::DaemonicCompiler::rustc::rustc_error::DiagnosticLevel,
pub messages: Vec<(DiagMessage, Style)>,
pub code: Option<ErrCode>,
pub lint_id: Option<LintExpectationId>,
pub span: MultiSpan,
pub children: Vec<Subdiag>,
pub suggestions: Suggestions,
pub args: DiagArgMap,
pub sort_span: Span,
pub is_lint: Option<IsLint>,
pub long_ty_path: Option<PathBuf>,
pub emitted_at: DiagLocation,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Subdiag {
pub level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::DiagnosticLevel,
pub messages: Vec<(DiagMessage, Style)>,
pub span: MultiSpan,
}
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
pub enum DiagnosticLevel {
Bug,
Fatal,
Error,
DelayedBug,
ForceWarning,
Warning,
Note,
OnceNote,
Help,
OnceHelp,
FailureNote,
Allow,
Expect,
}
#[derive(Copy, Clone)]
pub struct DiagnosticContextHandle<'a> {
pub dcx: &'a DiagCtxt,
pub tainted_with_errors: Option<&'a Cell<Option<ErrorGuaranteed>>>,
}
pub struct DiagCtxt {
pub(crate) inner: Lock<DiagCtxtInner>,
}
pub enum EmitOutcome<R> { Continue(R),
Recovered(RecoveredState),
MustStop(R),
}
pub struct RecoveredState {} }
mod implementations {
use std::backtrace::Backtrace;
use crate::{DiagCtxtHandle, DiagnosticContextHandle, Subdiagnostic};
use crate::Color;
use crate::ColorSpec;
use std::borrow::Cow;
use std::cell::Cell;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::thread::panicking;
use crate::daemonic::daemonic_contract::daemonic_result::diagnostic;
use super::structures::*;
use super::traits::*;
impl<'a> DiagnosticContextHandle<'a> {
#[track_caller]
pub fn struct_bug(self, msg: impl Into<Cow<'static, str>>) -> crate::Diag<'a, BugAbort> {
crate::Diag::new(self, crate::DiagnosticLevel::Bug, msg.into())
}
#[track_caller]
pub fn bug(self, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_bug(msg).emit()
}
#[track_caller]
pub fn struct_span_bug(
self,
span: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> crate::Diag<'a, BugAbort> {
self.struct_bug(msg).with_span(span)
}
#[track_caller]
pub fn span_bug(self, span: impl Into<MultiSpan>, msg: impl Into<Cow<'static, str>>) -> ! {
self.struct_span_bug(span, msg.into()).emit()
}
#[track_caller]
pub fn create_bug(self, bug: impl crate::Diagnostic<'a, BugAbort>) -> crate::Diag<'a, BugAbort> {
bug.into_diag(self, crate::DiagnosticLevel::Bug)
}
#[track_caller]
pub fn emit_bug(self, bug: impl crate::Diagnostic<'a, BugAbort>) -> ! {
self.create_bug(bug).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_fatal(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, FatalAbort> {
crate::Diag::new(self, crate::DiagnosticLevel::Fatal, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn fatal(self, msg: impl Into<DiagMessage>) -> ! {
self.struct_fatal(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_fatal(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::Diag<'a, FatalAbort> {
self.struct_fatal(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_fatal(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) -> ! {
self.struct_span_fatal(span, msg).emit()
}
#[track_caller]
pub fn create_fatal(self, fatal: impl crate::Diagnostic<'a, FatalAbort>) -> crate::Diag<'a, FatalAbort> {
fatal.into_diag(self, crate::DiagnosticLevel::Fatal)
}
#[track_caller]
pub fn emit_fatal(self, fatal: impl crate::Diagnostic<'a, FatalAbort>) -> ! {
self.create_fatal(fatal).emit()
}
#[track_caller]
pub fn create_almost_fatal(
self,
fatal: impl crate::Diagnostic<'a, crate::FatalError>,
) -> crate::Diag<'a, crate::FatalError> {
fatal.into_diag(self, crate::DiagnosticLevel::Fatal)
}
#[track_caller]
pub fn emit_almost_fatal(self, fatal: impl crate::Diagnostic<'a, crate::FatalError>) -> crate::FatalError {
self.create_almost_fatal(fatal).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_err(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a> {
crate::Diag::new(self, crate::DiagnosticLevel::Error, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn err(self, msg: impl Into<DiagMessage>) -> crate::ErrorGuaranteed {
self.struct_err(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_err(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::Diag<'a> {
self.struct_err(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_err(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::ErrorGuaranteed {
self.struct_span_err(span, msg).emit()
}
#[track_caller]
pub fn create_err(self, err: impl crate::Diagnostic<'a>) -> crate::Diag<'a> {
err.into_diag(self, crate::DiagnosticLevel::Error)
}
#[track_caller]
pub fn emit_err(self, err: impl crate::Diagnostic<'a>) -> crate::ErrorGuaranteed {
self.create_err(err).emit()
}
#[track_caller]
pub fn delayed_bug(self, msg: impl Into<Cow<'static, str>>) -> crate::ErrorGuaranteed {
crate::Diag::<crate::ErrorGuaranteed>::new(self, crate::DiagnosticLevel::DelayedBug, msg.into()).emit()
}
#[track_caller]
pub fn span_delayed_bug(
self,
sp: impl Into<MultiSpan>,
msg: impl Into<Cow<'static, str>>,
) -> crate::ErrorGuaranteed {
crate::Diag::<crate::ErrorGuaranteed>::new(self, crate::DiagnosticLevel::DelayedBug, msg.into()).with_span(sp).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_warn(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Warning, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn warn(self, msg: impl Into<DiagMessage>) {
self.struct_warn(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_warn(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::Diag<'a, ()> {
self.struct_warn(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_warn(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_warn(span, msg).emit()
}
#[track_caller]
pub fn create_warn(self, warning: impl crate::Diagnostic<'a, ()>) -> crate::Diag<'a, ()> {
warning.into_diag(self, crate::DiagnosticLevel::Warning)
}
#[track_caller]
pub fn emit_warn(self, warning: impl crate::Diagnostic<'a, ()>) {
self.create_warn(warning).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_note(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Note, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn note(&self, msg: impl Into<DiagMessage>) {
self.struct_note(msg).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_span_note(
self,
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
) -> crate::Diag<'a, ()> {
self.struct_note(msg).with_span(span)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn span_note(self, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
self.struct_span_note(span, msg).emit()
}
#[track_caller]
pub fn create_note(self, note: impl crate::Diagnostic<'a, ()>) -> crate::Diag<'a, ()> {
note.into_diag(self, crate::DiagnosticLevel::Note)
}
#[track_caller]
pub fn emit_note(self, note: impl crate::Diagnostic<'a, ()>) {
self.create_note(note).emit()
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_help(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Help, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_failure_note(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::FailureNote, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_allow(self, msg: impl Into<DiagMessage>) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Allow, msg)
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn struct_expect(self, msg: impl Into<DiagMessage>, id: LintExpectationId) -> crate::Diag<'a, ()> {
crate::Diag::new(self, crate::DiagnosticLevel::Expect, msg).with_lint_id(id)
}
}
impl<'a> DiagnosticContextHandle<'a> {
pub fn stash_diagnostic(
&self,
span: Span,
key: StashKey,
diag: DiagInner,
) -> Option<ErrorGuaranteed> {
let guar = match diag.level {
DiagnosticLevel::Bug | DiagnosticLevel::Fatal => {
self.span_bug(
span,
format!("invalid level in `stash_diagnostic`: {:?}", diag.level),
);
}
DiagnosticLevel::Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
DiagnosticLevel::DelayedBug => {
return self.inner.borrow_mut().emit_diagnostic(diag, self.tainted_with_errors);
}
DiagnosticLevel::ForceWarning
| DiagnosticLevel::Warning
| DiagnosticLevel::Note
| DiagnosticLevel::OnceNote
| DiagnosticLevel::Help
| DiagnosticLevel::OnceHelp
| DiagnosticLevel::FailureNote
| DiagnosticLevel::Allow
| DiagnosticLevel::Expect => None,
};
self.inner
.borrow_mut()
.stashed_diagnostics
.entry(key)
.or_default()
.insert(span.with_parent(None), (diag, guar));
guar
}
pub fn steal_non_err(self, span: Span, key: StashKey) -> Option<Diag<'a, ()>> {
let (diag, guar) = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
)?;
assert!(!diag.is_error());
assert!(guar.is_none());
Some(Diag::new_diagnostic(self, diag))
}
pub fn try_steal_modify_and_emit_err<F>(
self,
span: Span,
key: StashKey,
mut modify_err: F,
) -> Option<ErrorGuaranteed>
where
F: FnMut(&mut Diag<'_>),
{
let err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
);
err.map(|(err, guar)| {
assert_eq!(err.level, DiagnosticLevel::Error);
assert!(guar.is_some());
let mut err = Diag::<ErrorGuaranteed>::new_diagnostic(self, err);
modify_err(&mut err);
assert_eq!(err.level, DiagnosticLevel::Error);
err.emit()
})
}
pub fn try_steal_replace_and_emit_err(
self,
span: Span,
key: StashKey,
new_err: Diag<'_>,
) -> ErrorGuaranteed {
let old_err = self.inner.borrow_mut().stashed_diagnostics.get_mut(&key).and_then(
|stashed_diagnostics| stashed_diagnostics.swap_remove(&span.with_parent(None)),
);
match old_err {
Some((old_err, guar)) => {
assert_eq!(old_err.level, DiagnosticLevel::Error);
assert!(guar.is_some());
Diag::<ErrorGuaranteed>::new_diagnostic(self, old_err).cancel();
}
None => {}
};
new_err.emit()
}
pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool {
let inner = self.inner.borrow();
if let Some(stashed_diagnostics) = inner.stashed_diagnostics.get(&key)
&& !stashed_diagnostics.is_empty()
{
stashed_diagnostics.contains_key(&span.with_parent(None))
} else {
false
}
}
pub fn emit_stashed_diagnostics(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_stashed_diagnostics()
}
#[inline]
pub fn err_count(&self) -> usize {
let inner = self.inner.borrow();
inner.err_guars.len()
+ inner.lint_err_guars.len()
+ inner
.stashed_diagnostics
.values()
.map(|a| a.values().filter(|(_, guar)| guar.is_some()).count())
.sum::<usize>()
}
pub fn has_errors_excluding_lint_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_excluding_lint_errors()
}
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors()
}
pub fn has_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
self.inner.borrow().has_errors_or_delayed_bugs()
}
pub fn print_error_count(&self) {
let mut inner = self.inner.borrow_mut();
assert!(inner.stashed_diagnostics.is_empty());
if inner.treat_err_as_bug() {
return;
}
let warnings = match inner.deduplicated_warn_count {
0 => Cow::from(""),
1 => Cow::from("1 warning emitted"),
count => Cow::from(format!("{count} warnings emitted")),
};
let errors = match inner.deduplicated_err_count {
0 => Cow::from(""),
1 => Cow::from("1 error emitted"),
count => Cow::from(format!("{count} errors emitted")),
};
if inner.treat_warn_as_err() && !warnings.is_empty() {
inner.emit_diagnostic(
DiagInner::new(DiagnosticLevel::ForceWarning, DiagMessage::Str(warnings.clone().to_owned())),
None,
);
}
if !errors.is_empty() {
if !warnings.is_empty() {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::Error, format!("{errors}; {warnings}")),
None,
);
} else {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::Error, errors.clone().to_owned()), None);
}
} else if !warnings.is_empty() {
inner.emit_diagnostic(
DiagInner::new(DiagnosticLevel::ForceWarning, DiagMessage::Str(warnings.clone().to_owned())),
None,
);
}
match (errors.is_empty(), warnings.is_empty()) {
(true, true) => return,
(false, true) => {
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, "aborting due to previous error"), None);
}
(false, false) => {
let msg1 = "aborting due to previous error";
let msg2 = format!("For more information about this error, try `rustc --explain E{}`.", "");
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg1), None);
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg2), None);
}
(true, false) => {
let msg = "warnings emitted";
inner.emit_diagnostic(DiagInner::new(DiagnosticLevel::FailureNote, msg), None);
}
}
}
pub fn abort_if_errors(&self) {
let mut inner = self.inner.borrow_mut();
if !inner.has_errors().is_some() {
return;
}
inner.emit_stashed_diagnostics();
FatalError.raise();
}
pub fn must_teach(&self, code: ErrCode) -> bool {
self.inner.borrow().must_teach(&code)
}
pub fn emit_diagnostic(&self, diagnostic: DiagInner) -> Option<ErrorGuaranteed> {
self.inner.borrow_mut().emit_diagnostic(diagnostic, self.tainted_with_errors)
}
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
}
pub fn emit_future_breakage_report(&self) {
let mut inner = self.inner.borrow_mut();
if inner.emitted_diagnostics.is_empty() {
return;
}
}
pub fn emit_unused_externs(
&self,
lint_level: rustc_lint_defs::LintLevel,
loud: bool,
unused_externs: &[&str],
) {
let mut inner = self.inner.borrow_mut();
if loud && lint_level.is_error() {
inner.bump_err_count();
}
drop(inner);
for unused in unused_externs {
let unused = unused.to_string();
self.emit_diagnostic(DiagInner::new(
DiagnosticLevel::Allow,
format!("unused extern crate `{unused}`"),
));
}
}
pub fn steal_fulfilled_expectation_ids(&self) -> FxIndexSet<LintExpectationId> {
assert!(
self.inner.borrow().unstable_expect_diagnostics.is_empty(),
"`DiagnosticContextHandle::steal_fulfilled_expectation_ids` must be called before `DiagnosticContextHandle::drop`"
);
std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
}
pub fn flush_delayed(&self) {
self.inner.borrow_mut().flush_delayed()
}
#[track_caller]
pub fn set_must_produce_diag(&self) {
assert!(
self.inner.borrow().must_produce_diag.is_none(),
"should only need to collect a backtrace once"
);
self.inner.borrow_mut().must_produce_diag = Some(Backtrace::capture());
}
}
impl ! Send for FatalError {}
impl FatalError {
pub fn raise(self) -> ! {
std::panic::resume_unwind(Box::new(FatalErrorMarker))
}
}
impl std::fmt::Display for FatalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "fatal error")
}
}
impl std::error::Error for FatalError {}
impl ErrorGuaranteed {
#[deprecated = "should only be used in `DiagCtxtInner::emit_diagnostic`"]
pub fn unchecked_error_guaranteed() -> Self {
ErrorGuaranteed(())
}
pub fn raise_fatal(self) -> ! {
FatalError.raise()
}
}
impl diagnostic::EmissionGuarantee for ErrorGuaranteed {
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
todo!()
}
}
impl<G> ! Clone for crate::Diag<'_, G> {}
impl<G: diagnostic::EmissionGuarantee> Deref for crate::Diag<'_, G> {
type Target = DiagInner;
fn deref(&self) -> &DiagInner {
self.diag.as_ref().unwrap()
}
}
impl<G: diagnostic::EmissionGuarantee> DerefMut for crate::Diag<'_, G> {
fn deref_mut(&mut self) -> &mut DiagInner {
self.diag.as_mut().unwrap()
}
}
impl<G: diagnostic::EmissionGuarantee> Debug for crate::Diag<'_, G> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.diag.fmt(f)
}
}
impl<'a, G: diagnostic::EmissionGuarantee> crate::Diag<'a, G> {
#[rustc_lint_diagnostics]
#[track_caller]
pub fn new(dcx: DiagnosticContextHandle<'a>, level: diagnostic::DiagnosticLevel, message: impl Into<DiagMessage>) -> Self {
Self::new_diagnostic(dcx, DiagInner::new(level, message))
}
pub fn with_dcx(mut self, dcx: DiagnosticContextHandle<'_>) -> crate::Diag<'_, G> {
crate::Diag { dcx, diag: self.diag.take(), _marker: PhantomData }
}
#[track_caller]
pub(crate) fn new_diagnostic(dcx: DiagnosticContextHandle<'a>, diag: DiagInner) -> Self {
debug!("Created new diagnostic");
Self { dcx, diag: Some(Box::new(diag)), _marker: PhantomData }
}
#[rustc_lint_diagnostics]
#[track_caller]
pub fn downgrade_to_delayed_bug(&mut self) {
assert!(
matches!(self.level, Level::Error | Level::DelayedBug),
"downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
self.level
);
self.level = diagnostic::DiagnosticLevel::DelayedBug;
}
#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc = r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc = r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc = r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc = r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc = r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc = r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc = r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_label()`]."]
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
let msg = self.subdiagnostic_message_to_diagnostic_message(label);
self.span.push_span_label(span, msg);
self
}
#[doc = r" Appends a labeled span to the diagnostic."]
#[doc = r""]
#[doc = r" Labels are used to convey additional context for the diagnostic's primary span. They will"]
#[doc = r" be shown together with the original diagnostic's span, *not* with spans added by"]
#[doc = r" `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because"]
#[doc = r" the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed"]
#[doc = r" either."]
#[doc = r""]
#[doc = r" Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when"]
#[doc = r" the diagnostic was constructed. However, the label span is *not* considered a"]
#[doc = r#" ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is"#]
#[doc = r" primary."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_label()`]."]
pub fn with_span_label(mut self, span: Span, label: impl Into<SubdiagMessage>) -> Self {
self.span_label(span, label);
self
}
#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_labels()`]."]
pub fn span_labels(&mut self, spans: impl IntoIterator<Item=Span>, label: &str) -> &mut Self {
for span in spans {
self.span_label(span, label.to_string());
}
self
}
#[doc = r" Labels all the given spans with the provided label."]
#[doc = r" See [`Self::span_label()`] for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_labels()`]."]
pub fn with_span_labels(mut self, spans: impl IntoIterator<Item=Span>, label: &str) -> Self {
self.span_labels(spans, label);
self
}
#[rustc_lint_diagnostics]
pub fn replace_span_with(&mut self, after: Span, keep_label: bool) -> &mut Self {
let before = self.span.clone();
self.span(after);
for span_label in before.span_labels() {
if let Some(label) = span_label.label {
if span_label.is_primary && keep_label {
self.span.push_span_label(after, label);
} else {
self.span.push_span_label(span_label.span, label);
}
}
}
self
}
#[rustc_lint_diagnostics]
pub fn note_expected_found(
&mut self,
expected_label: &str,
expected: DiagStyledString,
found_label: &str,
found: DiagStyledString,
) -> &mut Self {
self.note_expected_found_extra(
expected_label,
expected,
found_label,
found,
DiagStyledString::normal(""),
DiagStyledString::normal(""),
)
}
#[rustc_lint_diagnostics]
pub fn note_expected_found_extra(
&mut self,
expected_label: &str,
expected: DiagStyledString,
found_label: &str,
found: DiagStyledString,
expected_extra: DiagStyledString,
found_extra: DiagStyledString,
) -> &mut Self {
let expected_label = expected_label.to_string();
let expected_label = if expected_label.is_empty() {
"expected".to_string()
} else {
format!("expected {expected_label}")
};
let found_label = found_label.to_string();
let found_label = if found_label.is_empty() {
"found".to_string()
} else {
format!("found {found_label}")
};
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
(expected_label.len() - found_label.len(), 0)
} else {
(0, found_label.len() - expected_label.len())
};
let mut msg = vec![StringPart::normal(format!(
"{}{} `",
" ".repeat(expected_padding),
expected_label
))];
msg.extend(expected.0);
msg.push(StringPart::normal(format!("`")));
msg.extend(expected_extra.0);
msg.push(StringPart::normal(format!("\n")));
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
msg.extend(found.0);
msg.push(StringPart::normal(format!("`")));
msg.extend(found_extra.0);
self.highlighted_note(msg);
self
}
#[rustc_lint_diagnostics]
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
StringPart::normal(format!("`{name}` from trait: `")),
StringPart::highlighted(signature),
StringPart::normal("`"),
]);
self
}
#[doc = r" Add a note attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::note()`]."]
pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Note, msg, MultiSpan::new());
self
}
#[doc = r" Add a note attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::note()`]."]
pub fn with_note(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.note(msg);
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Note, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_span_note(
&mut self,
span: impl Into<MultiSpan>,
msg: Vec<StringPart>,
) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Note, msg, span.into());
self
}
#[rustc_lint_diagnostics]
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceNote, msg, MultiSpan::new());
self
}
#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_note()`]."]
pub fn span_note(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Note, msg, sp.into());
self
}
#[doc = r" Prints the span with a note above it."]
#[doc = r" This is like [`Diag::note()`], but it gets its own span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_note()`]."]
pub fn with_span_note(mut self, sp: impl Into<MultiSpan>, msg: impl Into<SubdiagMessage>) -> Self {
self.span_note(sp, msg);
self
}
#[rustc_lint_diagnostics]
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceNote, msg, sp.into());
self
}
#[doc = r" Add a warning attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::warn()`]."]
pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Warning, msg, MultiSpan::new());
self
}
#[doc = r" Add a warning attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::warn()`]."]
pub fn with_warn(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.warn(msg);
self
}
#[rustc_lint_diagnostics]
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Warning, msg, sp.into());
self
}
#[doc = r" Add a help message attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::help()`]."]
pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Help, msg, MultiSpan::new());
self
}
#[doc = r" Add a help message attached to this diagnostic."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::help()`]."]
pub fn with_help(mut self, msg: impl Into<SubdiagMessage>) -> Self {
self.help(msg);
self
}
#[rustc_lint_diagnostics]
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::OnceHelp, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Help, msg, MultiSpan::new());
self
}
#[rustc_lint_diagnostics]
pub fn highlighted_span_help(
&mut self,
span: impl Into<MultiSpan>,
msg: Vec<StringPart>,
) -> &mut Self {
self.sub_with_highlights(diagnostic::DiagnosticLevel::Help, msg, span.into());
self
}
#[rustc_lint_diagnostics]
pub fn span_help<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
) -> &mut Self {
self.sub(diagnostic::DiagnosticLevel::Help, msg, sp.into());
self
}
#[rustc_lint_diagnostics]
pub fn disable_suggestions(&mut self) -> &mut Self {
self.suggestions = Suggestions::Disabled;
self
}
#[rustc_lint_diagnostics]
pub fn seal_suggestions(&mut self) -> &mut Self {
if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
let suggestions_slice = std::mem::take(suggestions).into_boxed_slice();
self.suggestions = Suggestions::Sealed(suggestions_slice);
}
self
}
#[rustc_lint_diagnostics]
fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
for subst in &suggestion.substitutions {
for part in &subst.parts {
let span = part.span;
let call_site = span.ctxt().outer_expn_data().call_site;
if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
return;
}
}
}
if let Suggestions::Enabled(suggestions) = &mut self.suggestions {
suggestions.push(suggestion);
}
}
#[doc = r" Show a suggestion that has multiple parts to it."]
#[doc = r" In other words, multiple changes need to be applied as part of this suggestion."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn multipart_suggestion(&mut self, msg: impl Into<SubdiagMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::ShowCode,
)
}
#[doc = r" Show a suggestion that has multiple parts to it."]
#[doc = r" In other words, multiple changes need to be applied as part of this suggestion."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::multipart_suggestion()`]."]
pub fn with_multipart_suggestion(mut self, msg: impl Into<SubdiagMessage>, suggestion: Vec<(Span, String)>, applicability: Applicability) -> Self {
self.multipart_suggestion(msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::ShowAlways,
)
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagMessage>,
mut suggestion: Vec<(Span, String)>,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
let mut seen = FxHashSet::default();
suggestion.retain(|(span, msg)| seen.insert((span.lo(), span.hi(), msg.clone())));
let parts = suggestion
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect::<Vec<_>>();
assert!(!parts.is_empty());
debug_assert_eq!(
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
None,
"Span must not be empty and have no suggestion",
);
debug_assert_eq!(
parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
None,
"suggestion must not have overlapping parts",
);
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution { parts }],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[rustc_lint_diagnostics]
pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
self.multipart_suggestion_with_style(
msg,
suggestion,
applicability,
SuggestionStyle::CompletelyHidden,
)
}
#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc = r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc = r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc = r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc = r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn span_suggestion(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::ShowCode,
);
self
}
#[doc = r" Prints out a message with a suggested edit of the code."]
#[doc = r""]
#[doc = r" In case of short messages and a simple suggestion, rustc displays it as a label:"]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" try adding parentheses: `(tup.0).1`"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" The message"]
#[doc = r""]
#[doc = r" * should not end in any punctuation (a `:` is added automatically)"]
#[doc = r#" * should not be a question (avoid language like "did you mean")"#]
#[doc = r#" * should not contain any phrases like "the following", "as shown", etc."#]
#[doc = r#" * may look like "to do xyz, use" or "to do xyz, use abc""#]
#[doc = r" * may contain a name of a function, variable, or type, but not whole expressions"]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion()`]."]
pub fn with_span_suggestion(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
debug_assert!(
!(sp.is_empty() && suggestion.to_string().is_empty()),
"Span must not be empty and have no suggestion"
);
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
}],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[doc = r" Always show the suggested change."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn span_suggestion_verbose(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::ShowAlways,
);
self
}
#[doc = r" Always show the suggested change."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_verbose()`]."]
pub fn with_span_suggestion_verbose(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion_verbose(sp, msg, suggestion, applicability);
self
}
#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn span_suggestions(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestions: impl IntoIterator<Item=String>, applicability: Applicability) -> &mut Self {
self.span_suggestions_with_style(
sp,
msg,
suggestions,
applicability,
SuggestionStyle::ShowCode,
)
}
#[doc = r" Prints out a message with multiple suggested edits of the code."]
#[doc = r" See also [`Diag::span_suggestion()`]."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestions()`]."]
pub fn with_span_suggestions(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestions: impl IntoIterator<Item=String>, applicability: Applicability) -> Self {
self.span_suggestions(sp, msg, suggestions, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestions_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestions: impl IntoIterator<Item=String>,
applicability: Applicability,
style: SuggestionStyle,
) -> &mut Self {
let substitutions = suggestions
.into_iter()
.map(|snippet| {
debug_assert!(
!(sp.is_empty() && snippet.is_empty()),
"Span must not be empty and have no suggestion"
);
Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }
})
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style,
applicability,
});
self
}
#[rustc_lint_diagnostics]
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagMessage>,
suggestions: impl IntoIterator<Item=Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
let substitutions = suggestions
.into_iter()
.map(|sugg| {
let mut parts = sugg
.into_iter()
.map(|(span, snippet)| SubstitutionPart { snippet, span })
.collect::<Vec<_>>();
parts.sort_unstable_by_key(|part| part.span);
assert!(!parts.is_empty());
debug_assert_eq!(
parts.iter().find(|part| part.span.is_empty() && part.snippet.is_empty()),
None,
"Span must not be empty and have no suggestion",
);
debug_assert_eq!(
parts.array_windows().find(|[a, b]| a.span.overlaps(b.span)),
None,
"suggestion must not have overlapping parts",
);
Substitution { parts }
})
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
style: SuggestionStyle::ShowCode,
applicability,
});
self
}
#[doc = r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn span_suggestion_short(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::HideCodeInline,
);
self
}
#[doc = r" Prints out a message with a suggested edit of the code. If the suggestion is presented"]
#[doc = r" inline, it will only show the message and not the suggestion."]
#[doc = r""]
#[doc = r" See `CodeSuggestion` for more information."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span_suggestion_short()`]."]
pub fn with_span_suggestion_short(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.span_suggestion_short(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::HideCodeAlways,
);
self
}
#[doc = r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc = r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc = r" need to be from the message, but we still want other tools to be able to apply them."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn tool_only_span_suggestion(&mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> &mut Self {
self.span_suggestion_with_style(
sp,
msg,
suggestion,
applicability,
SuggestionStyle::CompletelyHidden,
);
self
}
#[doc = r" Adds a suggestion to the JSON output that will not be shown in the CLI."]
#[doc = r""]
#[doc = r" This is intended to be used for suggestions that are *very* obvious in what the changes"]
#[doc = r" need to be from the message, but we still want other tools to be able to apply them."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::tool_only_span_suggestion()`]."]
pub fn with_tool_only_span_suggestion(mut self, sp: Span, msg: impl Into<SubdiagMessage>, suggestion: impl ToString, applicability: Applicability) -> Self {
self.tool_only_span_suggestion(sp, msg, suggestion, applicability);
self
}
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
subdiagnostic.add_to_diag(self);
self
}
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
}
#[doc = r" Add a span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span()`]."]
pub fn span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self {
self.span = sp.into();
if let Some(span) = self.span.primary_span() {
self.sort_span = span;
}
self
}
#[doc = r" Add a span."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::span()`]."]
pub fn with_span(mut self, sp: impl Into<MultiSpan>) -> Self {
self.span(sp);
self
}
#[rustc_lint_diagnostics]
pub fn is_lint(&mut self, name: String, has_future_breakage: bool) -> &mut Self {
self.is_lint = Some(IsLint { name, has_future_breakage });
self
}
#[doc = r" Add an error code."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::code()`]."]
pub fn code(&mut self, code: ErrCode) -> &mut Self {
self.code = Some(code);
self
}
#[doc = r" Add an error code."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::code()`]."]
pub fn with_code(mut self, code: ErrCode) -> Self {
self.code(code);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::lint_id()`]."]
pub fn lint_id(&mut self, id: LintExpectationId) -> &mut Self {
self.lint_id = Some(id);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::lint_id()`]."]
pub fn with_lint_id(mut self, id: LintExpectationId) -> Self {
self.lint_id(id);
self
}
#[doc = r" Add a primary message."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::primary_message()`]."]
pub fn primary_message(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
}
#[doc = r" Add a primary message."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::primary_message()`]."]
pub fn with_primary_message(mut self, msg: impl Into<DiagMessage>) -> Self {
self.primary_message(msg);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::arg()`]."]
pub fn arg(&mut self, name: impl Into<diagnostic::DiagArgName>, arg: impl crate::IntoDiagArg) -> &mut Self {
self.deref_mut().arg(name, arg);
self
}
#[doc = r" Add an argument."]
#[rustc_lint_diagnostics]
#[doc = "See [`Diag::arg()`]."]
pub fn with_arg(mut self, name: impl Into<diagnostic::DiagArgName>, arg: impl crate::IntoDiagArg) -> Self {
self.arg(name, arg);
self
}
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
self.deref().subdiagnostic_message_to_diagnostic_message(attr)
}
pub fn sub(&mut self, level: diagnostic::DiagnosticLevel, message: impl Into<SubdiagMessage>, span: MultiSpan) {
self.deref_mut().sub(level, message, span);
}
fn sub_with_highlights(&mut self, level: diagnostic::DiagnosticLevel, messages: Vec<StringPart>, span: MultiSpan) {
let messages = messages
.into_iter()
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
.collect();
let sub = crate::Subdiag { level, messages, span };
self.children.push(sub);
}
fn take_diag(&mut self) -> DiagInner {
if let Some(path) = &self.long_ty_path {
self.note(format!(
"the full name for the type has been written to '{}'",
path.display()
));
self.note("consider using `--verbose` to print the full type name to the console");
}
Box::into_inner(self.diag.take().unwrap())
}
pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> {
&mut self.long_ty_path
}
pub fn emit_producing_nothing(mut self) {
let diag = self.take_diag();
self.dcx.emit_diagnostic(diag);
}
pub fn emit_producing_error_guaranteed(mut self) -> ErrorGuaranteed {
let diag = self.take_diag();
assert!(
matches!(diag.level, Level::Error | Level::DelayedBug),
"invalid diagnostic level ({:?})",
diag.level,
);
let guar = self.dcx.emit_diagnostic(diag);
guar.unwrap()
}
#[track_caller]
pub fn emit(self) -> G::EmitResult {
G::emit_producing_guarantee(self)
}
#[track_caller]
pub fn emit_unless(mut self, delay: bool) -> G::EmitResult {
if delay {
self.downgrade_to_delayed_bug();
}
self.emit()
}
pub fn cancel(mut self) {
self.diag = None;
drop(self);
}
pub fn stash(mut self, span: Span, key: StashKey) -> Option<ErrorGuaranteed> {
let diag = self.take_diag();
self.dcx.stash_diagnostic(span, key, diag)
}
#[track_caller]
pub fn delay_as_bug(mut self) -> G::EmitResult {
self.downgrade_to_delayed_bug();
self.emit()
}
}
impl<G: diagnostic::EmissionGuarantee> Drop for crate::Diag<'_, G> {
fn drop(&mut self) {
match self.diag.take() {
Some(diag) if !panicking() => {
self.dcx.emit_diagnostic(DiagInner::new(
diagnostic::DiagnosticLevel::Bug,
DiagMessage::from("the following error was constructed but not emitted"),
));
self.dcx.emit_diagnostic(*diag);
panic!("error was constructed but not emitted");
}
_ => {}
}
}
}
impl fmt::Display for crate::DiagnosticLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_str().fmt(f)
}
}
impl crate::DiagnosticLevel {
pub fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
crate::DiagnosticLevel::Bug | crate::DiagnosticLevel::Fatal | crate::DiagnosticLevel::Error | crate::DiagnosticLevel::DelayedBug => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
crate::DiagnosticLevel::ForceWarning | crate::DiagnosticLevel::Warning => {
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
}
crate::DiagnosticLevel::Note | crate::DiagnosticLevel::OnceNote => {
spec.set_fg(Some(Color::Green)).set_intense(true);
}
crate::DiagnosticLevel::Help | crate::DiagnosticLevel::OnceHelp => {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
crate::DiagnosticLevel::FailureNote => {}
crate::DiagnosticLevel::Allow | crate::DiagnosticLevel::Expect => unreachable!(),
}
spec
}
pub fn to_str(self) -> &'static str {
match self {
crate::DiagnosticLevel::Bug | crate::DiagnosticLevel::DelayedBug => "error: internal compiler error",
crate::DiagnosticLevel::Fatal | crate::DiagnosticLevel::Error => "error",
crate::DiagnosticLevel::ForceWarning | crate::DiagnosticLevel::Warning => "warning",
crate::DiagnosticLevel::Note | crate::DiagnosticLevel::OnceNote => "note",
crate::DiagnosticLevel::Help | crate::DiagnosticLevel::OnceHelp => "help",
crate::DiagnosticLevel::FailureNote => "failure-note",
crate::DiagnosticLevel::Allow | crate::DiagnosticLevel::Expect => unreachable!(),
}
}
pub fn is_failure_note(&self) -> bool {
matches!(*self, DiagnosticLevel::FailureNote)
}
fn can_be_subdiag(&self) -> bool {
match self {
crate::DiagnosticLevel::Bug |
crate::DiagnosticLevel::DelayedBug |
crate::DiagnosticLevel::Fatal |
crate::DiagnosticLevel::Error |
crate::DiagnosticLevel::ForceWarning |
crate::DiagnosticLevel::FailureNote |
crate::DiagnosticLevel::Allow |
crate::DiagnosticLevel::Expect => false,
crate::DiagnosticLevel::Warning |
crate::DiagnosticLevel::Note |
crate::DiagnosticLevel::Help |
crate::DiagnosticLevel::OnceNote |
crate::DiagnosticLevel::OnceHelp => true,
}
}
}
impl diagnostic::EmissionGuarantee for () {
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
todo!()
}
}
impl diagnostic::EmissionGuarantee for FatalGuarantee {
const CONTINUEABLE: bool = false; type RecoveryHandler = diagnostic::FatalRecovery;
fn emit_producing_guarantee(diag: crate::Diag<'_, Self>) -> Self::EmitResult {
}
}
impl RecoveryHandler<FatalGuarantee> for FatalRecovery {
fn attempt_recovery(result: &FatalGuarantee) -> Option<RecoveredState> {
if result.kind.is_structurally_broken() {
None } else {
Some(RecoveredState::from_fatal(result))
}
}
}
impl EmissionGuarantee for FatalGuarantee {
const CONTINUEABLE: bool = false;
type RecoveryHandler = FatalRecovery;
fn emit_producing_guarantee(diag: Diag<'_, Self>) -> Self::EmitResult {
}
}
impl DiagInner {
#[track_caller]
pub fn new<M: Into<DiagMessage>>(level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel, message: M) -> Self {
DiagInner::new_with_messages(level, vec![(message.into(), Style::NoStyle)])
}
#[track_caller]
pub fn new_with_messages(level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel, messages: Vec<(DiagMessage, Style)>) -> Self {
DiagInner {
level,
lint_id: None,
messages,
code: None,
span: MultiSpan::new(),
children: vec![],
suggestions: Suggestions::Enabled(vec![]),
args: Default::default(),
sort_span: DUMMY_SP,
is_lint: None,
long_ty_path: None,
emitted_at: DiagLocation::caller(),
}
}
#[inline(always)]
pub fn level(&self) -> crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel {
self.level
}
pub fn is_error(&self) -> bool {
match self.level {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Bug | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Fatal | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Error | crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::DelayedBug => true,
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::ForceWarning
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Warning
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Note
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::OnceNote
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Help
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::OnceHelp
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::FailureNote
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Allow
| crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::Expect => false,
}
}
pub(crate) fn has_future_breakage(&self) -> bool {
matches!(self.is_lint, Some(IsLint { has_future_breakage: true, .. }))
}
pub(crate) fn is_force_warn(&self) -> bool {
match self.level {
crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel::ForceWarning => {
assert!(self.is_lint.is_some());
true
}
_ => false,
}
}
pub fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
let msg =
self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
msg.with_subdiagnostic_message(attr.into())
}
pub(crate) fn sub(
&mut self,
level: crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel,
message: impl Into<SubdiagMessage>,
span: MultiSpan,
) {
let sub = Subdiag {
level,
messages: vec![(
self.subdiagnostic_message_to_diagnostic_message(message),
Style::NoStyle,
)],
span,
};
self.children.push(sub);
}
pub(crate) fn arg(&mut self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) {
self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path));
}
fn keys(
&self,
) -> (
&crate::daemonic::daemonic_contract::daemonic_result::diagnostic::structures::DiagnosticLevel,
&[(DiagMessage, Style)],
&Option<ErrCode>,
&MultiSpan,
&[Subdiag],
&Suggestions,
Vec<(&DiagArgName, &DiagArgValue)>,
&Option<IsLint>,
) {
(
&self.level,
&self.messages,
&self.code,
&self.span,
&self.children,
&self.suggestions,
self.args.iter().collect(),
&self.is_lint,
)
}
}
impl Hash for DiagInner {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.keys().hash(state);
}
}
impl PartialEq for DiagInner {
fn eq(&self, other: &Self) -> bool {
self.keys() == other.keys()
}
}
impl IntoDiagArg for DiagArgValue {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
self
}
}
impl<'a> std::ops::Deref for DiagCtxtHandle<'a> {
type Target = &'a DiagCtxt;
fn deref(&self) -> &Self::Target {
&self.dcx
}
}
}
pub use traits::*;
pub use structures::*;
pub use implementations::*;
#[macro_export]
macro_rules! debug {
(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+)
);
(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
);
(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(name: $name:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(name: $name:expr, $($arg:tt)+ ) => (
$crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+)
);
(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
);
(target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
);
(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
);
(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
);
(target: $target:expr, $($arg:tt)+ ) => (
$crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
);
(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($field)+ },
$($arg)+
)
);
(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($k).+ = $($field)*}
)
);
(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ ?$($k).+ = $($field)*}
)
);
(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ %$($k).+ = $($field)*}
)
);
(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ $($k).+, $($field)*}
)
);
(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ ?$($k).+, $($field)*}
)
);
(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{ %$($k).+, $($field)*}
)
);
(parent: $parent:expr, $($arg:tt)+) => (
$crate::event!(
target: module_path!(),
parent: $parent,
$crate::Level::DEBUG,
{},
$($arg)+
)
);
({ $($field:tt)+ }, $($arg:tt)+ ) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($field)+ },
$($arg)+
)
);
($($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+ = $($field)*}
)
);
(?$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+ = $($field)*}
)
);
(%$($k:ident).+ = $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+ = $($field)*}
)
);
($($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+, $($field)*}
)
);
(?$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+, $($field)*}
)
);
(%$($k:ident).+, $($field:tt)*) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+, $($field)*}
)
);
(?$($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ ?$($k).+ }
)
);
(%$($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ %$($k).+ }
)
);
($($k:ident).+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
{ $($k).+ }
)
);
($($arg:tt)+) => (
$crate::event!(
target: module_path!(),
$crate::Level::DEBUG,
$($arg)+
)
);
}
}
pub(crate) mod subdiagnostic {
use crate::EmissionGuarantee;
#[rustc_diagnostic_item = "Subdiagnostic"]
pub trait Subdiagnostic
where
Self: Sized,
{
fn add_to_diag<GUARANTEE: EmissionGuarantee>(
self,
diag: &mut Diag<'_, GUARANTEE>,
);
}
}
pub(crate) mod repairable {
use super::severity_types::{GlassCracked, GlassState, SeverityType};
use super::*;
use crate::daemonic::Daemonic;
use crate::daemonic::daemonic_contract::IntoDaemonicResult;
use crate::{DaemonicError, DaemonicResult};
pub trait SeverityHandler<FORMAT, PARTIAL> {
type Context;
type Output: IntoDaemonicResult<FORMAT, PARTIAL>;
type Error: for<'e> DaemonicError<'e, FORMAT, PARTIAL>;
fn handle_stable(&self, _state: &GlassStable, _ctx: &Self::Context) -> DaemonicResult<Self::Output, Self::Error> {
DaemonicResult::Success(Self::Output::default())
}
fn handle_note(&self, _state: &GlassNote, _ctx: &Self::Context) -> DaemonicResult<Self::Output, Self::Error> {
DaemonicResult::Success(Self::Output::default())
}
fn handle_help(&self, _state: &GlassHelp, _ctx: &Self::Context) -> DaemonicResult<Self::Output, Self::Error> {
DaemonicResult::Success(Self::Output::default())
}
fn handle_suggestion(
&self,
_state: &GlassSuggestion,
_ctx: &Self::Context,
) -> DaemonicResult<Self::Output, Self::Error> {
DaemonicResult::Success(Self::Output::default())
}
fn handle_cracked_holding(
&self,
_state: &GlassCracked,
_ctx: &Self::Context,
) -> DaemonicResult<Self::Output, Self::Error> {
DaemonicResult::Success(Self::Output::default())
}
fn handle_cracked_contained<R>(
&self,
state: &GlassCracked,
ctx: &mut Self::Context,
action: impl FnOnce(&Self::Error, &mut Self::Context) -> Option<R>,
) -> DaemonicResult<R, Self::Error> {
let error = Self::Error::from_cracked(state); match action(&error, ctx) {
Some(repaired) => DaemonicResult::Success(repaired),
None => DaemonicResult::Failure(error),
}
}
fn handle_fracture<R>(
&self,
state: &GlassFracture,
ctx: &mut Self::Context,
action: impl FnOnce(&Self::Error, &mut Self::Context) -> Option<R>,
) -> DaemonicResult<R, Self::Error> {
let error = Self::Error::from_fracture(state);
match action(&error, ctx) {
Some(repaired) => DaemonicResult::Success(repaired),
None => DaemonicResult::Failure(error),
}
}
fn handle_warp<R>(
&self,
state: &GlassWarp,
ctx: &mut Self::Context,
action: impl FnOnce(&Self::Error, &mut Self::Context) -> Option<R>,
) -> DaemonicResult<R, Self::Error> {
let error = Self::Error::from_warp(state);
match action(&error, ctx) {
Some(repaired) => DaemonicResult::Success(repaired),
None => DaemonicResult::Failure(error),
}
}
fn handle_shattered<R>(
&self,
state: &GlassShattered,
ctx: &mut Self::Context,
action: impl FnOnce(&Self::Error, &mut Self::Context) -> Option<R>,
) -> DaemonicResult<R, Self::Error> {
let error = Self::Error::from_shattered(state);
match action(&error, ctx) {
Some(recovered) => DaemonicResult::Success(recovered),
None => DaemonicResult::Failure(error),
}
}
fn handle<Repair>(&self, severity: &SeverityType, ctx: &mut Self::Context, _repair: impl FnOnce(&Self::Error, &mut Self::Context)
-> Option<Repair>) -> DaemonicResult<Self::Output, Self::Error>
{
match severity {
SeverityType::GlassStable(s) => {
self.handle_stable(s, ctx)
}
SeverityType::GlassNote(note) => {
self.handle_note(note, ctx)
}
SeverityType::GlassSuggestion(sug) => {
self.handle_suggestion(sug, ctx)
}
SeverityType::GlassHelp(h) => {
self.handle_help(h, ctx)
}
SeverityType::GlassCracked(crack) => {
self.handle_cracked(crack, ctx, |_error, _ctx| None::<Self::Output>)
}
SeverityType::GlassFracture(f) => {
self.handle_fracture(f, ctx, |_error, _ctx| None::<Self::Output>)
}
SeverityType::GlassWarp(w) => {
self.handle_warp(w, ctx, |_error, _ctx| None::<Self::Output>)
}
SeverityType::GlassShattered(shatter) => {
self.handle_shattered(shatter, ctx, |_error, _ctx| None::<Self::Output>)
}
}
}
}
struct DaemonicHandler<CONTEXT, ACTION, R> {
context: CONTEXT,
action: Option<fn(&SeverityType, CONTEXT) -> ACTION>,
}
}
pub(crate) mod severity_types {
use super::mirror_chemistry::{MirrorType, ReflectionProperties};
pub trait GlassState<'state>: Send + Sync + 'state {
type Mirror<'mirrortype>: MirrorType<'mirrortype>;
type Cause<'mirrortype>: Severity;
fn from_reflection(props: ReflectionProperties) -> Self;
fn is_recoverable(&self) -> bool { false }
fn can_cascade(&self) -> bool { false }
fn dominance(&self) -> u8;
fn stable<'stable>() -> fn(GlassStable) -> SeverityType;
fn fracture(props: &ReflectionProperties) -> fn(GlassFracture) -> SeverityType;
fn warp(props: &ReflectionProperties) -> fn(GlassWarp) -> SeverityType;
fn shatter<'impossible>() -> fn(GlassShattered) -> SeverityType;
fn note<'note>() -> fn(GlassNote) -> SeverityType;
fn suggestion<'suggestion>() -> fn(GlassSuggestion) -> SeverityType;
fn help<'help>() -> fn(GlassHelp) -> SeverityType;
}
pub trait Severity: Send + Sync {
type Mirror<'mirrortype>: MirrorType<'mirrortype>;
const RECOVERABLE: bool;
const CAN_CASCADE: bool;
const DOMINANCE: u8;
fn on_observer(&self) -> SeverityAction;
}
pub(crate) enum SeverityAction {
Continue,
Warn,
Halt,
Abort,
}
pub enum SeverityType {
GlassStable(GlassStable),
GlassHelp(GlassHelp),
GlassSuggestion(GlassSuggestion),
GlassNote(GlassNote),
GlassCracked(GlassCracked),
GlassFracture(GlassFracture),
GlassWarp(GlassWarp),
GlassShattered(GlassShattered),
}
impl<R> From<GlassStable> for SeverityType {
fn from(s: GlassStable) -> Self {
SeverityType::GlassStable(s)
}
}
impl<R> SeverityType {
pub fn as_glass_state(&self) -> &dyn GlassState<Cause=impl Severity, Mirror=impl MirrorType> {
match self {
SeverityType::GlassStable(s) => s,
SeverityType::GlassHelp(s) => s,
SeverityType::GlassSuggestion(s) => s,
SeverityType::GlassNote(s) => s,
SeverityType::GlassFracture(s) => s,
SeverityType::GlassWarp(s) => s,
SeverityType::GlassShattered(s) => s,
SeverityType::GlassCracked(s) => { s }
}
}
}
pub enum SeverityCause {
EntropyTermination(entropy::EntropyTermination),
}
use crate::daemonic::daemonic_contract::daemonic_result::mirror_chemistry::elements::{SPECULAR, ABSORPTIVE};
pub(crate) struct GlassStable;
pub(crate) struct GlassHelp;
pub(crate) struct GlassSuggestion;
pub(crate) struct GlassNote;
pub(crate) struct GlassFracture;
pub(crate) struct GlassWarp;
pub(crate) struct GlassShattered;
pub(crate) struct GlassCracked;
pub(crate) mod entropy;
pub(crate) struct SeverityContext<SEVERITY: Severity> {
pub state: SEVERITY,
pub cause: SeverityCause,
pub recoverable_here: bool,
}
}
pub(crate) use diagnostic::DiagnosticLevel;
}
pub(crate) mod partial_types {
use std::marker::PhantomPinned;
fn dummy() -> PhantomPinned {
PhantomPinned
}
}
}
pub(crate) struct DaemonicID<FORMAT, PARTIAL> {
id: u32,
nickname: Option<dyn DaemonicBinary<FORMAT, PARTIAL, Error=impl DaemonicError<FORMAT, PARTIAL>>>,
}
}
use std::fmt::Debug;
use daemonic::{
daemonic_core::{
*,
observation::{
debug::{
*,
}
},
},
daemonic_contract::{
daemonic_result::{
severity_types::*,
mirror_chemistry::*,
diagnostic::*,
subdiagnostic::*,
},
*,
},
};
pub use daemonic::{
daemonic_contract::{
daemonic_result::{
subdiagnostic::{
Subdiagnostic,
},
diagnostic::{
DiagnosticLevel,
DiagnosticContextHandle as DiagCtxtHandle,
DiagnosticContextHandle,
Diagnostic,
Diag,
DiagInner,
DiagCtxt,
IntoDiagArg,
Subdiag,
DiagArgValue,
ErrorGuaranteed,
FatalError,
FatalErrorMarker,
},
}
}
};
#[allow(non_snake_case)]
pub trait DaemonicError<
'ERROR, FORMAT,
PARTIAL,
DIAGNOSTIC = dyn Diagnostic, SUBDIAGNOSTIC = dyn Subdiagnostic, CONTEXT = dyn ErrorContext, SEVERITY = SeverityType, META = dyn MetaData >:
DaemonicObservation<FORMAT, PARTIAL>
+ Send
+ Sync
+ Sized + core::fmt::Debug
+ ErrorContext<'ERROR>
+ 'ERROR
where
CONTEXT: ErrorContext<'ERROR>,
META: MetaData<'ERROR>,
SEVERITY: GlassState<'ERROR>,
{
#[must_use]
fn position(&self) -> &Position;
#[must_use]
fn context(&self) -> &CONTEXT;
#[must_use]
fn severity(&self) -> SEVERITY;
fn wrap_in(self, parent_position: Position) -> Self;
fn emit_diagnostic(&self) -> DIAGNOSTIC { None }
fn emit_subdiagnostic(&self) -> SUBDIAGNOSTIC { None }
fn metadata(&self) -> &META { &None }
fn is_recoverable(&self) -> bool {
self.severity().is_recoverable() }
fn source_position(&self) -> Option<&Position> {
None
}
}
#[allow(non_snake_case)]
trait ErrorContext<'ERROR>: Send + Sync + 'ERROR {
fn position(&self) -> &Position;
fn timestamp(&self) -> Timestamp;
}
impl DaemonicError for DummyStruct {}
struct DummyStruct;
trait MetaData<'meta>: Send + Sync + 'meta {}
pub trait EnumerationRouter {}
pub(crate) struct Position<'segments> {
segments: Vec<&'segments str>,
}
pub(crate) struct Timestamp {
timestamp: PhantomPinned,
}
impl MetaData<'_> for () {}
use std::marker::{PhantomData, PhantomPinned};
pub use opaque_dependencies::termcolor::*;
use crate::daemonic::daemonic_core::observation::DaemonicObservation;