Rename iced_sentinel to iced_beacon and refactor its API
This commit is contained in:
parent
aaf396256e
commit
57033dc4d0
19 changed files with 596 additions and 438 deletions
|
|
@ -106,7 +106,7 @@ members = [
|
|||
"highlighter",
|
||||
"renderer",
|
||||
"runtime",
|
||||
"sentinel",
|
||||
"beacon",
|
||||
"tiny_skia",
|
||||
"wgpu",
|
||||
"widget",
|
||||
|
|
@ -126,6 +126,7 @@ keywords = ["gui", "ui", "graphics", "interface", "widgets"]
|
|||
|
||||
[workspace.dependencies]
|
||||
iced = { version = "0.13.0-dev", path = "." }
|
||||
iced_beacon = { version = "0.13.0-dev", path = "beacon" }
|
||||
iced_core = { version = "0.13.0-dev", path = "core" }
|
||||
iced_debug = { version = "0.13.0-dev", path = "debug" }
|
||||
iced_futures = { version = "0.13.0-dev", path = "futures" }
|
||||
|
|
@ -133,7 +134,6 @@ iced_graphics = { version = "0.13.0-dev", path = "graphics" }
|
|||
iced_highlighter = { version = "0.13.0-dev", path = "highlighter" }
|
||||
iced_renderer = { version = "0.13.0-dev", path = "renderer" }
|
||||
iced_runtime = { version = "0.13.0-dev", path = "runtime" }
|
||||
iced_sentinel = { version = "0.13.0-dev", path = "sentinel" }
|
||||
iced_tiny_skia = { version = "0.13.0-dev", path = "tiny_skia" }
|
||||
iced_wgpu = { version = "0.13.0-dev", path = "wgpu" }
|
||||
iced_widget = { version = "0.13.0-dev", path = "widget" }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "iced_sentinel"
|
||||
name = "iced_beacon"
|
||||
description = "A client/server protocol to monitor and supervise iced applications"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
|
@ -17,6 +17,7 @@ iced_core.features = ["serde"]
|
|||
bincode.workspace = true
|
||||
futures.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
tokio.workspace = true
|
||||
tokio.features = ["rt", "rt-multi-thread", "net", "sync", "time", "io-util", "macros"]
|
||||
123
beacon/src/client.rs
Normal file
123
beacon/src/client.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
use crate::core::time::{Duration, SystemTime};
|
||||
use crate::span;
|
||||
use crate::theme;
|
||||
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::{self, AsyncWriteExt};
|
||||
use tokio::net;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
pub const SERVER_ADDRESS: &str = "127.0.0.1:9167";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Client {
|
||||
sender: mpsc::Sender<Message>,
|
||||
_handle: Arc<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Message {
|
||||
Connected {
|
||||
at: SystemTime,
|
||||
name: String,
|
||||
version: Version,
|
||||
},
|
||||
EventLogged {
|
||||
at: SystemTime,
|
||||
event: Event,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Event {
|
||||
ThemeChanged(theme::Palette),
|
||||
SpanStarted(span::Stage),
|
||||
SpanFinished(span::Stage, Duration),
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn log(&self, event: Event) {
|
||||
let _ = self.sender.try_send(Message::EventLogged {
|
||||
at: SystemTime::now(),
|
||||
event,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn connect(name: String) -> Client {
|
||||
let (sender, receiver) = mpsc::channel(100);
|
||||
|
||||
let handle = std::thread::spawn(move || run(name, receiver));
|
||||
|
||||
Client {
|
||||
sender,
|
||||
_handle: Arc::new(handle),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn run(name: String, mut receiver: mpsc::Receiver<Message>) {
|
||||
let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))
|
||||
.expect("Parse package version");
|
||||
|
||||
loop {
|
||||
match _connect().await {
|
||||
Ok(mut stream) => {
|
||||
let _ = send(
|
||||
&mut stream,
|
||||
Message::Connected {
|
||||
at: SystemTime::now(),
|
||||
name: name.clone(),
|
||||
version: version.clone(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
while let Some(output) = receiver.recv().await {
|
||||
match send(&mut stream, output).await {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"Error sending message to server: {error}"
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
time::sleep(time::Duration::from_secs(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _connect() -> Result<net::TcpStream, io::Error> {
|
||||
log::debug!("Attempting to connect to server...");
|
||||
let stream = net::TcpStream::connect(SERVER_ADDRESS).await?;
|
||||
|
||||
stream.set_nodelay(true)?;
|
||||
stream.writable().await?;
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
async fn send(
|
||||
stream: &mut net::TcpStream,
|
||||
message: Message,
|
||||
) -> Result<(), io::Error> {
|
||||
let bytes = bincode::serialize(&message).expect("Encode input message");
|
||||
let size = bytes.len() as u64;
|
||||
|
||||
stream.write_all(&size.to_be_bytes()).await?;
|
||||
stream.write_all(&bytes).await?;
|
||||
stream.flush().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
184
beacon/src/lib.rs
Normal file
184
beacon/src/lib.rs
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
pub use iced_core as core;
|
||||
pub use semver::Version;
|
||||
|
||||
pub mod client;
|
||||
pub mod span;
|
||||
|
||||
mod stream;
|
||||
|
||||
pub use client::Client;
|
||||
pub use span::Span;
|
||||
|
||||
use crate::core::theme;
|
||||
use crate::core::time::{Duration, SystemTime};
|
||||
|
||||
use futures::{SinkExt, Stream};
|
||||
use tokio::io::{self, AsyncReadExt};
|
||||
use tokio::net;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
Connected {
|
||||
at: SystemTime,
|
||||
name: String,
|
||||
version: Version,
|
||||
},
|
||||
Disconnected {
|
||||
at: SystemTime,
|
||||
},
|
||||
ThemeChanged {
|
||||
at: SystemTime,
|
||||
palette: theme::Palette,
|
||||
},
|
||||
SpanFinished {
|
||||
at: SystemTime,
|
||||
duration: Duration,
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub fn at(&self) -> SystemTime {
|
||||
match self {
|
||||
Self::Connected { at, .. }
|
||||
| Self::Disconnected { at, .. }
|
||||
| Self::ThemeChanged { at, .. }
|
||||
| Self::SpanFinished { at, .. } => *at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> impl Stream<Item = Event> {
|
||||
stream::channel(|mut output| async move {
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
loop {
|
||||
let Ok(mut stream) = connect().await else {
|
||||
delay().await;
|
||||
continue;
|
||||
};
|
||||
|
||||
loop {
|
||||
match receive(&mut stream, &mut buffer).await {
|
||||
Ok(message) => {
|
||||
match message {
|
||||
client::Message::Connected {
|
||||
at,
|
||||
name,
|
||||
version,
|
||||
} => {
|
||||
let _ = output
|
||||
.send(Event::Connected {
|
||||
at,
|
||||
name,
|
||||
version,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
client::Message::EventLogged { at, event } => {
|
||||
match event {
|
||||
client::Event::ThemeChanged(palette) => {
|
||||
let _ = output
|
||||
.send(Event::ThemeChanged {
|
||||
at,
|
||||
palette,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
client::Event::SpanStarted(_) => {}
|
||||
client::Event::SpanFinished(
|
||||
stage,
|
||||
duration,
|
||||
) => {
|
||||
let span = match stage {
|
||||
span::Stage::Boot => Span::Boot,
|
||||
span::Stage::Update => Span::Update,
|
||||
span::Stage::View(window) => {
|
||||
Span::View { window }
|
||||
}
|
||||
span::Stage::Layout(window) => {
|
||||
Span::Layout { window }
|
||||
}
|
||||
span::Stage::Interact(window) => {
|
||||
Span::Interact { window }
|
||||
}
|
||||
span::Stage::Draw(window) => {
|
||||
Span::Draw { window }
|
||||
}
|
||||
span::Stage::Present(window) => {
|
||||
Span::Present { window }
|
||||
}
|
||||
span::Stage::Custom(
|
||||
window,
|
||||
name,
|
||||
) => Span::Custom { window, name },
|
||||
};
|
||||
|
||||
let _ = output
|
||||
.send(Event::SpanFinished {
|
||||
at,
|
||||
duration,
|
||||
span,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(Error::IOFailed(_)) => {
|
||||
let _ = output
|
||||
.send(Event::Disconnected {
|
||||
at: SystemTime::now(),
|
||||
})
|
||||
.await;
|
||||
|
||||
delay().await;
|
||||
break;
|
||||
}
|
||||
Err(Error::DecodingFailed(error)) => {
|
||||
log::warn!("Error decoding beacon output: {error}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn connect() -> Result<net::TcpStream, io::Error> {
|
||||
let listener = net::TcpListener::bind(client::SERVER_ADDRESS).await?;
|
||||
|
||||
let (stream, _) = listener.accept().await?;
|
||||
|
||||
stream.set_nodelay(true)?;
|
||||
stream.readable().await?;
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
async fn receive(
|
||||
stream: &mut net::TcpStream,
|
||||
buffer: &mut Vec<u8>,
|
||||
) -> Result<client::Message, Error> {
|
||||
let size = stream.read_u64().await? as usize;
|
||||
|
||||
if buffer.len() < size {
|
||||
buffer.resize(size, 0);
|
||||
}
|
||||
|
||||
let _n = stream.read_exact(&mut buffer[..size]).await?;
|
||||
|
||||
Ok(bincode::deserialize(buffer)?)
|
||||
}
|
||||
|
||||
async fn delay() {
|
||||
tokio::time::sleep(Duration::from_secs(2)).await;
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum Error {
|
||||
#[error("input/output operation failed: {0}")]
|
||||
IOFailed(#[from] io::Error),
|
||||
#[error("decoding failed: {0}")]
|
||||
DecodingFailed(#[from] Box<bincode::ErrorKind>),
|
||||
}
|
||||
61
beacon/src/span.rs
Normal file
61
beacon/src/span.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use crate::core::window;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Span {
|
||||
Boot,
|
||||
Update,
|
||||
View { window: window::Id },
|
||||
Layout { window: window::Id },
|
||||
Interact { window: window::Id },
|
||||
Draw { window: window::Id },
|
||||
Present { window: window::Id },
|
||||
Custom { window: window::Id, name: String },
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub fn stage(&self) -> Stage {
|
||||
match self {
|
||||
Span::Boot => Stage::Boot,
|
||||
Span::Update => Stage::Update,
|
||||
Span::View { window } => Stage::View(*window),
|
||||
Span::Layout { window } => Stage::Layout(*window),
|
||||
Span::Interact { window } => Stage::Interact(*window),
|
||||
Span::Draw { window } => Stage::Draw(*window),
|
||||
Span::Present { window } => Stage::Present(*window),
|
||||
Span::Custom { window, name } => {
|
||||
Stage::Custom(*window, name.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum Stage {
|
||||
Boot,
|
||||
Update,
|
||||
View(window::Id),
|
||||
Layout(window::Id),
|
||||
Interact(window::Id),
|
||||
Draw(window::Id),
|
||||
Present(window::Id),
|
||||
Custom(window::Id, String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Stage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Stage::Boot => "Boot",
|
||||
Stage::Update => "Update",
|
||||
Stage::View(_) => "View",
|
||||
Stage::Layout(_) => "Layout",
|
||||
Stage::Interact(_) => "Interact",
|
||||
Stage::Draw(_) => "Draw",
|
||||
Stage::Present(_) => "Present",
|
||||
Stage::Custom(_, name) => name,
|
||||
})
|
||||
}
|
||||
}
|
||||
15
beacon/src/stream.rs
Normal file
15
beacon/src/stream.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use futures::channel::mpsc;
|
||||
use futures::stream::{self, Stream, StreamExt};
|
||||
use futures::Future;
|
||||
|
||||
pub fn channel<T, F>(f: impl Fn(mpsc::Sender<T>) -> F) -> impl Stream<Item = T>
|
||||
where
|
||||
F: Future<Output = ()>,
|
||||
{
|
||||
let (sender, receiver) = mpsc::channel(1);
|
||||
|
||||
stream::select(
|
||||
receiver,
|
||||
stream::once(f(sender)).filter_map(|_| async { None }),
|
||||
)
|
||||
}
|
||||
|
|
@ -11,13 +11,13 @@ categories.workspace = true
|
|||
keywords.workspace = true
|
||||
|
||||
[features]
|
||||
enable = ["dep:iced_sentinel", "dep:once_cell"]
|
||||
enable = ["dep:iced_beacon", "dep:once_cell"]
|
||||
|
||||
[dependencies]
|
||||
iced_core.workspace = true
|
||||
|
||||
iced_sentinel.workspace = true
|
||||
iced_sentinel.optional = true
|
||||
iced_beacon.workspace = true
|
||||
iced_beacon.optional = true
|
||||
|
||||
once_cell.workspace = true
|
||||
once_cell.optional = true
|
||||
|
|
|
|||
198
debug/src/lib.rs
198
debug/src/lib.rs
|
|
@ -3,45 +3,49 @@ pub use iced_core as core;
|
|||
use crate::core::theme;
|
||||
use crate::core::window;
|
||||
|
||||
pub use internal::Timer;
|
||||
pub use internal::Span;
|
||||
|
||||
pub fn open_axe() {}
|
||||
pub fn init(name: &str) {
|
||||
internal::init(name);
|
||||
}
|
||||
|
||||
pub fn open_comet() {}
|
||||
|
||||
pub fn log_message(_message: &impl std::fmt::Debug) {}
|
||||
|
||||
pub fn theme_changed(palette: theme::Palette) {
|
||||
internal::theme_changed(palette);
|
||||
pub fn theme_changed(f: impl FnOnce() -> Option<theme::Palette>) {
|
||||
internal::theme_changed(f);
|
||||
}
|
||||
|
||||
pub fn boot_time() -> Timer {
|
||||
internal::boot_time()
|
||||
pub fn boot() -> Span {
|
||||
internal::boot()
|
||||
}
|
||||
|
||||
pub fn update_time() -> Timer {
|
||||
internal::update_time()
|
||||
pub fn update() -> Span {
|
||||
internal::update()
|
||||
}
|
||||
|
||||
pub fn view_time(window: window::Id) -> Timer {
|
||||
internal::view_time(window)
|
||||
pub fn view(window: window::Id) -> Span {
|
||||
internal::view(window)
|
||||
}
|
||||
|
||||
pub fn layout_time(window: window::Id) -> Timer {
|
||||
internal::layout_time(window)
|
||||
pub fn layout(window: window::Id) -> Span {
|
||||
internal::layout(window)
|
||||
}
|
||||
|
||||
pub fn interact_time(window: window::Id) -> Timer {
|
||||
internal::interact_time(window)
|
||||
pub fn interact(window: window::Id) -> Span {
|
||||
internal::interact(window)
|
||||
}
|
||||
|
||||
pub fn draw_time(window: window::Id) -> Timer {
|
||||
internal::draw_time(window)
|
||||
pub fn draw(window: window::Id) -> Span {
|
||||
internal::draw(window)
|
||||
}
|
||||
|
||||
pub fn render_time(window: window::Id) -> Timer {
|
||||
internal::render_time(window)
|
||||
pub fn present(window: window::Id) -> Span {
|
||||
internal::present(window)
|
||||
}
|
||||
|
||||
pub fn time(window: window::Id, name: impl AsRef<str>) -> Timer {
|
||||
pub fn time(window: window::Id, name: impl AsRef<str>) -> Span {
|
||||
internal::time(window, name)
|
||||
}
|
||||
|
||||
|
|
@ -52,158 +56,156 @@ pub fn skip_next_timing() {
|
|||
#[cfg(feature = "enable")]
|
||||
mod internal {
|
||||
use crate::core::theme;
|
||||
use crate::core::time::{Instant, SystemTime};
|
||||
use crate::core::time::Instant;
|
||||
use crate::core::window;
|
||||
|
||||
use iced_sentinel::client::{self, Client};
|
||||
use iced_sentinel::timing::{self, Timing};
|
||||
use iced_beacon as beacon;
|
||||
|
||||
use beacon::client::{self, Client};
|
||||
use beacon::span;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{Mutex, MutexGuard};
|
||||
use std::sync::atomic::{self, AtomicBool};
|
||||
use std::sync::RwLock;
|
||||
|
||||
pub fn theme_changed(palette: theme::Palette) {
|
||||
let mut debug = lock();
|
||||
pub fn init(name: &str) {
|
||||
name.clone_into(&mut NAME.write().expect("Write application name"));
|
||||
}
|
||||
|
||||
if debug.last_palette.as_ref() != Some(&palette) {
|
||||
debug.sentinel.report_theme_change(palette);
|
||||
pub fn theme_changed(f: impl FnOnce() -> Option<theme::Palette>) {
|
||||
let Some(palette) = f() else {
|
||||
return;
|
||||
};
|
||||
|
||||
debug.last_palette = Some(palette);
|
||||
if LAST_PALETTE.read().expect("Read last palette").as_ref()
|
||||
!= Some(&palette)
|
||||
{
|
||||
BEACON.log(client::Event::ThemeChanged(palette));
|
||||
|
||||
*LAST_PALETTE.write().expect("Write last palette") = Some(palette);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn boot_time() -> Timer {
|
||||
timer(timing::Stage::Boot)
|
||||
pub fn boot() -> Span {
|
||||
span(span::Stage::Boot)
|
||||
}
|
||||
|
||||
pub fn update_time() -> Timer {
|
||||
timer(timing::Stage::Update)
|
||||
pub fn update() -> Span {
|
||||
span(span::Stage::Update)
|
||||
}
|
||||
|
||||
pub fn view_time(window: window::Id) -> Timer {
|
||||
timer(timing::Stage::View(window))
|
||||
pub fn view(window: window::Id) -> Span {
|
||||
span(span::Stage::View(window))
|
||||
}
|
||||
|
||||
pub fn layout_time(window: window::Id) -> Timer {
|
||||
timer(timing::Stage::Layout(window))
|
||||
pub fn layout(window: window::Id) -> Span {
|
||||
span(span::Stage::Layout(window))
|
||||
}
|
||||
|
||||
pub fn interact_time(window: window::Id) -> Timer {
|
||||
timer(timing::Stage::Interact(window))
|
||||
pub fn interact(window: window::Id) -> Span {
|
||||
span(span::Stage::Interact(window))
|
||||
}
|
||||
|
||||
pub fn draw_time(window: window::Id) -> Timer {
|
||||
timer(timing::Stage::Draw(window))
|
||||
pub fn draw(window: window::Id) -> Span {
|
||||
span(span::Stage::Draw(window))
|
||||
}
|
||||
|
||||
pub fn render_time(window: window::Id) -> Timer {
|
||||
timer(timing::Stage::Render(window))
|
||||
pub fn present(window: window::Id) -> Span {
|
||||
span(span::Stage::Present(window))
|
||||
}
|
||||
|
||||
pub fn time(window: window::Id, name: impl AsRef<str>) -> Timer {
|
||||
timer(timing::Stage::Custom(window, name.as_ref().to_owned()))
|
||||
pub fn time(window: window::Id, name: impl AsRef<str>) -> Span {
|
||||
span(span::Stage::Custom(window, name.as_ref().to_owned()))
|
||||
}
|
||||
|
||||
pub fn skip_next_timing() {
|
||||
lock().skip_next_timing = true;
|
||||
SKIP_NEXT_SPAN.store(true, atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
fn timer(stage: timing::Stage) -> Timer {
|
||||
Timer {
|
||||
stage,
|
||||
fn span(span: span::Stage) -> Span {
|
||||
BEACON.log(client::Event::SpanStarted(span.clone()));
|
||||
|
||||
Span {
|
||||
span,
|
||||
start: Instant::now(),
|
||||
start_system_time: SystemTime::now(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Timer {
|
||||
stage: timing::Stage,
|
||||
pub struct Span {
|
||||
span: span::Stage,
|
||||
start: Instant,
|
||||
start_system_time: SystemTime,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
impl Span {
|
||||
pub fn finish(self) {
|
||||
let mut debug = lock();
|
||||
|
||||
if debug.skip_next_timing {
|
||||
debug.skip_next_timing = false;
|
||||
if SKIP_NEXT_SPAN.fetch_and(false, atomic::Ordering::Relaxed) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug.sentinel.report_timing(Timing {
|
||||
stage: self.stage,
|
||||
start: self.start_system_time,
|
||||
duration: self.start.elapsed(),
|
||||
});
|
||||
BEACON.log(client::Event::SpanFinished(
|
||||
self.span,
|
||||
self.start.elapsed(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Debug {
|
||||
sentinel: Client,
|
||||
last_palette: Option<theme::Palette>,
|
||||
skip_next_timing: bool,
|
||||
}
|
||||
|
||||
fn lock() -> MutexGuard<'static, Debug> {
|
||||
static DEBUG: Lazy<Mutex<Debug>> = Lazy::new(|| {
|
||||
Mutex::new(Debug {
|
||||
sentinel: client::connect(),
|
||||
last_palette: None,
|
||||
skip_next_timing: false,
|
||||
})
|
||||
static BEACON: Lazy<Client> = Lazy::new(|| {
|
||||
client::connect(NAME.read().expect("Read application name").to_owned())
|
||||
});
|
||||
|
||||
DEBUG.lock().expect("Acquire debug lock")
|
||||
}
|
||||
static NAME: RwLock<String> = RwLock::new(String::new());
|
||||
static LAST_PALETTE: RwLock<Option<theme::Palette>> = RwLock::new(None);
|
||||
static SKIP_NEXT_SPAN: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "enable"))]
|
||||
mod internal {
|
||||
use crate::core::theme;
|
||||
use crate::core::window;
|
||||
use crate::style::theme;
|
||||
|
||||
pub fn theme_changed(_palette: theme::Palette) {}
|
||||
pub fn init(_name: &str) {}
|
||||
|
||||
pub fn boot_time() -> Timer {
|
||||
Timer
|
||||
pub fn theme_changed(_f: impl FnOnce() -> Option<theme::Palette>) {}
|
||||
|
||||
pub fn boot() -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn update_time() -> Timer {
|
||||
Timer
|
||||
pub fn update() -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn view_time(_window: window::Id) -> Timer {
|
||||
Timer
|
||||
pub fn view(_window: window::Id) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn layout_time(_window: window::Id) -> Timer {
|
||||
Timer
|
||||
pub fn layout(_window: window::Id) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn interact_time(_window: window::Id) -> Timer {
|
||||
Timer
|
||||
pub fn interact(_window: window::Id) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn draw_time(_window: window::Id) -> Timer {
|
||||
Timer
|
||||
pub fn draw(_window: window::Id) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn render_time(_window: window::Id) -> Timer {
|
||||
Timer
|
||||
pub fn present(_window: window::Id) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn time(_window: window::Id, _name: impl AsRef<str>) -> Timer {
|
||||
Timer
|
||||
pub fn time(_window: window::Id, _name: impl AsRef<str>) -> Span {
|
||||
Span
|
||||
}
|
||||
|
||||
pub fn skip_next_timing() {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Timer;
|
||||
pub struct Span;
|
||||
|
||||
impl Timer {
|
||||
impl Span {
|
||||
pub fn finish(self) {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
docs/logo-no-shadow.svg
Normal file
2
docs/logo-no-shadow.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="140" height="140" fill="none" version="1.1" viewBox="35 31 179 171"><rect x="42" y="31.001" width="169.9" height="169.9" rx="49.815" fill="url(#paint1_linear)"/><path d="m182.62 65.747-28.136 28.606-6.13-6.0291 28.136-28.606 6.13 6.0291zm-26.344 0.218-42.204 42.909-6.13-6.029 42.204-42.909 6.13 6.0291zm-61.648 23.913c5.3254-5.3831 10.65-10.765 21.569-21.867l6.13 6.0291c-10.927 11.11-16.258 16.498-21.587 21.885-4.4007 4.4488-8.8009 8.8968-16.359 16.573l31.977 8.358 25.968-26.402 6.13 6.0292-25.968 26.402 8.907 31.908 42.138-42.087 6.076 6.083-49.109 49.05-45.837-12.628-13.394-45.646 1.7714-1.801c10.928-11.111 16.258-16.499 21.588-21.886zm28.419 70.99-8.846-31.689-31.831-8.32 9.1945 31.335 31.482 8.674zm47.734-56.517 7.122-7.1221-6.08-6.0797-7.147 7.1474-30.171 30.674 6.13 6.029 30.146-30.649z" clip-rule="evenodd" fill="url(#paint2_linear)" fill-rule="evenodd"/><defs><filter id="filter0_f" x="55" y="47.001" width="144" height="168" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur" stdDeviation="2"/></filter><linearGradient id="paint0_linear" x1="127" x2="127" y1="51.001" y2="211" gradientUnits="userSpaceOnUse"><stop offset=".052083"/><stop stop-opacity=".08" offset="1"/></linearGradient><linearGradient id="paint1_linear" x1="212" x2="57.5" y1="31.001" y2="189" gradientUnits="userSpaceOnUse"><stop stop-color="#00A3FF" offset="0"/><stop stop-color="#30f" offset="1"/></linearGradient><linearGradient id="paint2_linear" x1="86.098" x2="206.01" y1="158.28" y2="35.327" gradientUnits="userSpaceOnUse"><stop stop-color="#fff" offset="0"/><stop stop-color="#fff" offset="1"/></linearGradient></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -102,7 +102,7 @@ where
|
|||
bounds,
|
||||
);
|
||||
|
||||
let interact_timer = debug::interact_time(window::Id::MAIN);
|
||||
let interact_span = debug::interact(window::Id::MAIN);
|
||||
let mut messages = Vec::new();
|
||||
|
||||
let (_, event_statuses) = user_interface.update(
|
||||
|
|
@ -125,13 +125,13 @@ where
|
|||
|
||||
self.queued_events.clear();
|
||||
messages.append(&mut self.queued_messages);
|
||||
drop(interact_timer);
|
||||
interact_span.finish();
|
||||
|
||||
let command = if messages.is_empty() {
|
||||
let draw_timer = debug::draw_time(window::Id::MAIN);
|
||||
let draw_span = debug::draw(window::Id::MAIN);
|
||||
self.mouse_interaction =
|
||||
user_interface.draw(renderer, theme, style, cursor);
|
||||
drop(draw_timer);
|
||||
draw_span.finish();
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
|
||||
|
|
@ -145,9 +145,9 @@ where
|
|||
Command::batch(messages.into_iter().map(|message| {
|
||||
debug::log_message(&message);
|
||||
|
||||
let update_timer = debug::update_time();
|
||||
let update_span = debug::update();
|
||||
let command = self.program.update(message);
|
||||
drop(update_timer);
|
||||
update_span.finish();
|
||||
|
||||
command
|
||||
}));
|
||||
|
|
@ -159,10 +159,10 @@ where
|
|||
bounds,
|
||||
);
|
||||
|
||||
let draw_timer = debug::draw_time(window::Id::MAIN);
|
||||
let draw_spawn = debug::draw(window::Id::MAIN);
|
||||
self.mouse_interaction =
|
||||
user_interface.draw(renderer, theme, style, cursor);
|
||||
drop(draw_timer);
|
||||
draw_spawn.finish();
|
||||
|
||||
self.cache = Some(user_interface.into_cache());
|
||||
|
||||
|
|
@ -214,13 +214,13 @@ fn build_user_interface<'a, P: Program>(
|
|||
renderer: &mut P::Renderer,
|
||||
size: Size,
|
||||
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
|
||||
let view_timer = debug::view_time(window::Id::MAIN);
|
||||
let view_span = debug::view(window::Id::MAIN);
|
||||
let view = program.view();
|
||||
drop(view_timer);
|
||||
view_span.finish();
|
||||
|
||||
let layout_timer = debug::layout_time(window::Id::MAIN);
|
||||
let layout_span = debug::layout(window::Id::MAIN);
|
||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
||||
drop(layout_timer);
|
||||
layout_span.finish();
|
||||
|
||||
user_interface
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
use crate::core::time::SystemTime;
|
||||
use crate::theme;
|
||||
use crate::{Input, Timing, SOCKET_ADDRESS};
|
||||
|
||||
use tokio::io::{self, AsyncWriteExt};
|
||||
use tokio::net;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Client {
|
||||
sender: mpsc::Sender<Input>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub fn report_theme_change(&mut self, palette: theme::Palette) {
|
||||
let _ = self.sender.try_send(Input::ThemeChanged {
|
||||
at: SystemTime::now(),
|
||||
palette,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn report_timing(&mut self, timing: Timing) {
|
||||
let _ = self.sender.try_send(Input::TimingMeasured(timing));
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn connect() -> Client {
|
||||
let (sender, receiver) = mpsc::channel(1_000);
|
||||
|
||||
std::thread::spawn(move || run(receiver));
|
||||
|
||||
Client { sender }
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn run(mut receiver: mpsc::Receiver<Input>) {
|
||||
let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))
|
||||
.expect("Parse package version");
|
||||
|
||||
loop {
|
||||
match _connect().await {
|
||||
Ok(mut stream) => {
|
||||
let _ = send(
|
||||
&mut stream,
|
||||
Input::Connected {
|
||||
at: SystemTime::now(),
|
||||
version: version.clone(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
while let Some(input) = receiver.recv().await {
|
||||
match send(&mut stream, input).await {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
log::warn!("Error sending message to sentinel server: {error}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
time::sleep(time::Duration::from_secs(2)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn _connect() -> Result<io::BufStream<net::TcpStream>, io::Error> {
|
||||
log::debug!("Attempting to connect sentinel to server...");
|
||||
let stream = net::TcpStream::connect(SOCKET_ADDRESS).await?;
|
||||
|
||||
stream.set_nodelay(true)?;
|
||||
stream.writable().await?;
|
||||
|
||||
Ok(io::BufStream::new(stream))
|
||||
}
|
||||
|
||||
async fn send(
|
||||
stream: &mut io::BufStream<net::TcpStream>,
|
||||
input: Input,
|
||||
) -> Result<(), io::Error> {
|
||||
let bytes = bincode::serialize(&input).expect("Encode input message");
|
||||
let size = bytes.len() as u64;
|
||||
|
||||
stream.write_all(&size.to_be_bytes()).await?;
|
||||
stream.write_all(&bytes).await?;
|
||||
stream.flush().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
pub use iced_core as core;
|
||||
pub use semver::Version;
|
||||
|
||||
pub mod client;
|
||||
pub mod timing;
|
||||
|
||||
use crate::core::theme;
|
||||
use crate::core::time::SystemTime;
|
||||
use crate::timing::Timing;
|
||||
|
||||
use futures::future;
|
||||
use futures::stream::{self, Stream, StreamExt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::{self, AsyncReadExt, BufStream};
|
||||
use tokio::net;
|
||||
|
||||
pub const SOCKET_ADDRESS: &str = "127.0.0.1:9167";
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Input {
|
||||
Connected {
|
||||
at: SystemTime,
|
||||
version: Version,
|
||||
},
|
||||
ThemeChanged {
|
||||
at: SystemTime,
|
||||
palette: theme::Palette,
|
||||
},
|
||||
TimingMeasured(Timing),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Event {
|
||||
Connected {
|
||||
at: SystemTime,
|
||||
version: Version,
|
||||
},
|
||||
Disconnected {
|
||||
at: SystemTime,
|
||||
},
|
||||
ThemeChanged {
|
||||
at: SystemTime,
|
||||
palette: theme::Palette,
|
||||
},
|
||||
TimingMeasured(Timing),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub fn at(&self) -> SystemTime {
|
||||
match self {
|
||||
Self::Connected { at, .. }
|
||||
| Self::Disconnected { at }
|
||||
| Self::ThemeChanged { at, .. } => *at,
|
||||
Self::TimingMeasured(timing) => timing.start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> impl Stream<Item = Event> {
|
||||
enum State {
|
||||
Disconnected,
|
||||
Connected(BufStream<net::TcpStream>),
|
||||
}
|
||||
|
||||
stream::unfold(State::Disconnected, |state| async {
|
||||
match state {
|
||||
State::Disconnected => match connect().await {
|
||||
Ok(stream) => {
|
||||
let stream = BufStream::new(stream);
|
||||
|
||||
Some((None, State::Connected(stream)))
|
||||
}
|
||||
Err(_error) => Some((None, State::Disconnected)),
|
||||
},
|
||||
State::Connected(stream) => match receive(stream).await {
|
||||
Ok((stream, input)) => {
|
||||
let event = match input {
|
||||
Input::Connected { at, version } => {
|
||||
Event::Connected { at, version }
|
||||
}
|
||||
Input::TimingMeasured(timing) => {
|
||||
Event::TimingMeasured(timing)
|
||||
}
|
||||
Input::ThemeChanged { at, palette } => {
|
||||
Event::ThemeChanged { at, palette }
|
||||
}
|
||||
};
|
||||
|
||||
Some((Some(event), State::Connected(stream)))
|
||||
}
|
||||
Err(_) => Some((
|
||||
Some(Event::Disconnected {
|
||||
at: SystemTime::now(),
|
||||
}),
|
||||
State::Disconnected,
|
||||
)),
|
||||
},
|
||||
}
|
||||
})
|
||||
.filter_map(future::ready)
|
||||
}
|
||||
|
||||
async fn connect() -> Result<net::TcpStream, io::Error> {
|
||||
let listener = net::TcpListener::bind(SOCKET_ADDRESS).await?;
|
||||
|
||||
let (stream, _) = listener.accept().await?;
|
||||
|
||||
stream.set_nodelay(true)?;
|
||||
stream.readable().await?;
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
async fn receive(
|
||||
mut stream: BufStream<net::TcpStream>,
|
||||
) -> Result<(BufStream<net::TcpStream>, Input), io::Error> {
|
||||
let mut bytes = Vec::new();
|
||||
|
||||
loop {
|
||||
let size = stream.read_u64().await? as usize;
|
||||
|
||||
if bytes.len() < size {
|
||||
bytes.resize(size, 0);
|
||||
}
|
||||
|
||||
let _n = stream.read_exact(&mut bytes[..size]).await?;
|
||||
|
||||
match bincode::deserialize(&bytes) {
|
||||
Ok(input) => {
|
||||
return Ok((stream, input));
|
||||
}
|
||||
Err(_) => {
|
||||
log::warn!("Error decoding sentinel message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
use crate::core::time::{Duration, SystemTime};
|
||||
use crate::core::window;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Timing {
|
||||
pub stage: Stage,
|
||||
pub start: SystemTime,
|
||||
pub duration: Duration,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
pub enum Stage {
|
||||
Boot,
|
||||
Update,
|
||||
View(window::Id),
|
||||
Layout(window::Id),
|
||||
Interact(window::Id),
|
||||
Draw(window::Id),
|
||||
Render(window::Id),
|
||||
Custom(window::Id, String),
|
||||
}
|
||||
|
||||
impl fmt::Display for Stage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Boot => write!(f, "Boot"),
|
||||
Self::Update => write!(f, "Update"),
|
||||
Self::View(_) => write!(f, "View"),
|
||||
Self::Layout(_) => write!(f, "Layout"),
|
||||
Self::Interact(_) => write!(f, "Interact"),
|
||||
Self::Draw(_) => write!(f, "Draw"),
|
||||
Self::Render(_) => write!(f, "Render"),
|
||||
Self::Custom(_, name) => f.write_str(name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +118,9 @@ where
|
|||
/// The data needed to initialize your [`Application`].
|
||||
type Flags;
|
||||
|
||||
/// Returns the unique name of the [`Application`].
|
||||
fn name() -> &'static str;
|
||||
|
||||
/// Initializes the [`Application`] with the flags provided to
|
||||
/// [`run`] as part of the [`Settings`].
|
||||
///
|
||||
|
|
@ -250,6 +253,10 @@ where
|
|||
{
|
||||
type Flags = A::Flags;
|
||||
|
||||
fn name() -> &'static str {
|
||||
A::name()
|
||||
}
|
||||
|
||||
fn new(flags: Self::Flags) -> (Self, Command<A::Message>) {
|
||||
let (app, command) = A::new(flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,12 @@ where
|
|||
type Renderer = Renderer;
|
||||
type Executor = executor::Default;
|
||||
|
||||
fn name() -> &'static str {
|
||||
let type_name = std::any::type_name::<State>();
|
||||
|
||||
type_name.split("::").next().unwrap_or(type_name)
|
||||
}
|
||||
|
||||
fn load(&self) -> Command<Self::Message> {
|
||||
Command::none()
|
||||
}
|
||||
|
|
@ -211,6 +217,10 @@ impl<P: Definition> Program<P> {
|
|||
)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
self.program.title(&self.state)
|
||||
}
|
||||
|
|
@ -431,6 +441,8 @@ pub trait Definition: Sized {
|
|||
/// The executor of the program.
|
||||
type Executor: Executor;
|
||||
|
||||
fn name() -> &'static str;
|
||||
|
||||
fn load(&self) -> Command<Self::Message>;
|
||||
|
||||
fn update(
|
||||
|
|
@ -484,12 +496,16 @@ fn with_title<P: Definition>(
|
|||
type Renderer = P::Renderer;
|
||||
type Executor = P::Executor;
|
||||
|
||||
fn title(&self, state: &Self::State) -> String {
|
||||
self.title.title(state)
|
||||
}
|
||||
|
||||
fn load(&self) -> Command<Self::Message> {
|
||||
self.program.load()
|
||||
}
|
||||
|
||||
fn title(&self, state: &Self::State) -> String {
|
||||
self.title.title(state)
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn update(
|
||||
|
|
@ -553,6 +569,10 @@ fn with_load<P: Definition>(
|
|||
Command::batch([self.program.load(), (self.load)()])
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn update(
|
||||
&self,
|
||||
state: &mut Self::State,
|
||||
|
|
@ -621,6 +641,10 @@ fn with_subscription<P: Definition>(
|
|||
(self.subscription)(state)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn load(&self) -> Command<Self::Message> {
|
||||
self.program.load()
|
||||
}
|
||||
|
|
@ -686,6 +710,10 @@ fn with_theme<P: Definition>(
|
|||
(self.theme)(state)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn load(&self) -> Command<Self::Message> {
|
||||
self.program.load()
|
||||
}
|
||||
|
|
@ -755,6 +783,10 @@ fn with_style<P: Definition>(
|
|||
(self.style)(state, theme)
|
||||
}
|
||||
|
||||
fn name() -> &'static str {
|
||||
P::name()
|
||||
}
|
||||
|
||||
fn load(&self) -> Command<Self::Message> {
|
||||
self.program.load()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub use settings::Settings;
|
|||
pub use geometry::Geometry;
|
||||
|
||||
use crate::core::{
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Transformation,
|
||||
};
|
||||
use crate::graphics::text::{Editor, Paragraph};
|
||||
use crate::graphics::Viewport;
|
||||
|
|
@ -477,7 +477,7 @@ impl core::text::Renderer for Renderer {
|
|||
impl core::image::Renderer for Renderer {
|
||||
type Handle = core::image::Handle;
|
||||
|
||||
fn measure_image(&self, handle: &Self::Handle) -> Size<u32> {
|
||||
fn measure_image(&self, handle: &Self::Handle) -> core::Size<u32> {
|
||||
self.image_cache.borrow_mut().measure_image(handle)
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +503,7 @@ impl core::image::Renderer for Renderer {
|
|||
|
||||
#[cfg(feature = "svg")]
|
||||
impl core::svg::Renderer for Renderer {
|
||||
fn measure_svg(&self, handle: &core::svg::Handle) -> Size<u32> {
|
||||
fn measure_svg(&self, handle: &core::svg::Handle) -> core::Size<u32> {
|
||||
self.image_cache.borrow_mut().measure_svg(handle)
|
||||
}
|
||||
|
||||
|
|
@ -539,7 +539,7 @@ impl graphics::geometry::Renderer for Renderer {
|
|||
type Geometry = Geometry;
|
||||
type Frame = geometry::Frame;
|
||||
|
||||
fn new_frame(&self, size: Size) -> Self::Frame {
|
||||
fn new_frame(&self, size: core::Size) -> Self::Frame {
|
||||
geometry::Frame::new(size)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ where
|
|||
/// The data needed to initialize your [`Application`].
|
||||
type Flags;
|
||||
|
||||
/// Returns the unique name of the [`Application`].
|
||||
fn name() -> &'static str;
|
||||
|
||||
/// Initializes the [`Application`] with the flags provided to
|
||||
/// [`run`] as part of the [`Settings`].
|
||||
///
|
||||
|
|
@ -156,7 +159,8 @@ where
|
|||
use futures::Future;
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
let boot_timer = debug::boot_time();
|
||||
debug::init(A::name());
|
||||
let boot_span = debug::boot();
|
||||
|
||||
let event_loop = EventLoop::with_user_event()
|
||||
.build()
|
||||
|
|
@ -193,7 +197,7 @@ where
|
|||
control_sender,
|
||||
init_command,
|
||||
settings.fonts,
|
||||
boot_timer,
|
||||
boot_span,
|
||||
));
|
||||
|
||||
let context = task::Context::from_waker(task::noop_waker_ref());
|
||||
|
|
@ -498,7 +502,7 @@ async fn run_instance<A, E, C>(
|
|||
mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
|
||||
init_command: Command<A::Message>,
|
||||
fonts: Vec<Cow<'static, [u8]>>,
|
||||
boot_timer: debug::Timer,
|
||||
boot_span: debug::Span,
|
||||
) where
|
||||
A: Application + 'static,
|
||||
E: Executor + 'static,
|
||||
|
|
@ -554,7 +558,7 @@ async fn run_instance<A, E, C>(
|
|||
&window,
|
||||
);
|
||||
runtime.track(application.subscription().into_recipes());
|
||||
boot_timer.finish();
|
||||
boot_span.finish();
|
||||
|
||||
let mut user_interface = ManuallyDrop::new(build_user_interface(
|
||||
&application,
|
||||
|
|
@ -608,12 +612,12 @@ async fn run_instance<A, E, C>(
|
|||
if viewport_version != current_viewport_version {
|
||||
let logical_size = state.logical_size();
|
||||
|
||||
let layout_timer = debug::layout_time(window::Id::MAIN);
|
||||
let layout_span = debug::layout(window::Id::MAIN);
|
||||
user_interface = ManuallyDrop::new(
|
||||
ManuallyDrop::into_inner(user_interface)
|
||||
.relayout(logical_size, &mut renderer),
|
||||
);
|
||||
layout_timer.finish();
|
||||
layout_span.finish();
|
||||
|
||||
compositor.configure_surface(
|
||||
&mut surface,
|
||||
|
|
@ -660,7 +664,7 @@ async fn run_instance<A, E, C>(
|
|||
|
||||
runtime.broadcast(redraw_event, core::event::Status::Ignored);
|
||||
|
||||
let draw_timer = debug::draw_time(window::Id::MAIN);
|
||||
let draw_span = debug::draw(window::Id::MAIN);
|
||||
let new_mouse_interaction = user_interface.draw(
|
||||
&mut renderer,
|
||||
state.theme(),
|
||||
|
|
@ -670,7 +674,7 @@ async fn run_instance<A, E, C>(
|
|||
state.cursor(),
|
||||
);
|
||||
redraw_pending = false;
|
||||
draw_timer.finish();
|
||||
draw_span.finish();
|
||||
|
||||
if new_mouse_interaction != mouse_interaction {
|
||||
window.set_cursor(conversion::mouse_interaction(
|
||||
|
|
@ -680,7 +684,7 @@ async fn run_instance<A, E, C>(
|
|||
mouse_interaction = new_mouse_interaction;
|
||||
}
|
||||
|
||||
let render_timer = debug::render_time(window::Id::MAIN);
|
||||
let present_span = debug::present(window::Id::MAIN);
|
||||
match compositor.present(
|
||||
&mut renderer,
|
||||
&mut surface,
|
||||
|
|
@ -688,7 +692,7 @@ async fn run_instance<A, E, C>(
|
|||
state.background_color(),
|
||||
) {
|
||||
Ok(()) => {
|
||||
render_timer.finish();
|
||||
present_span.finish();
|
||||
}
|
||||
Err(error) => match error {
|
||||
// This is an unrecoverable error.
|
||||
|
|
@ -733,7 +737,7 @@ async fn run_instance<A, E, C>(
|
|||
redraw_request: None,
|
||||
}
|
||||
} else {
|
||||
let interact_timer = debug::interact_time(window::Id::MAIN);
|
||||
let interact_span = debug::interact(window::Id::MAIN);
|
||||
let (interface_state, statuses) = user_interface.update(
|
||||
&events,
|
||||
state.cursor(),
|
||||
|
|
@ -747,7 +751,7 @@ async fn run_instance<A, E, C>(
|
|||
{
|
||||
runtime.broadcast(event, status);
|
||||
}
|
||||
interact_timer.finish();
|
||||
interact_span.finish();
|
||||
|
||||
interface_state
|
||||
};
|
||||
|
|
@ -842,13 +846,13 @@ pub fn build_user_interface<'a, A: Application>(
|
|||
where
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
let view_timer = debug::view_time(window::Id::MAIN);
|
||||
let view_span = debug::view(window::Id::MAIN);
|
||||
let view = application.view();
|
||||
view_timer.finish();
|
||||
view_span.finish();
|
||||
|
||||
let layout_timer = debug::layout_time(window::Id::MAIN);
|
||||
let layout_span = debug::layout(window::Id::MAIN);
|
||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
||||
layout_timer.finish();
|
||||
layout_span.finish();
|
||||
|
||||
user_interface
|
||||
}
|
||||
|
|
@ -875,9 +879,9 @@ pub fn update<A: Application, C, E: Executor>(
|
|||
for message in messages.drain(..) {
|
||||
debug::log_message(&message);
|
||||
|
||||
let update_timer = debug::update_time();
|
||||
let update_span = debug::update();
|
||||
let command = runtime.enter(|| application.update(message));
|
||||
update_timer.finish();
|
||||
update_span.finish();
|
||||
|
||||
run_command(
|
||||
application,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ where
|
|||
let theme = application.theme();
|
||||
let appearance = application.style(&theme);
|
||||
|
||||
let _ = application::DefaultStyle::palette(&theme)
|
||||
.map(debug::theme_changed);
|
||||
debug::theme_changed(|| application::DefaultStyle::palette(&theme));
|
||||
|
||||
let viewport = {
|
||||
let physical_size = window.inner_size();
|
||||
|
|
@ -216,7 +215,8 @@ where
|
|||
self.theme = application.theme();
|
||||
self.appearance = application.style(&self.theme);
|
||||
|
||||
let _ = application::DefaultStyle::palette(&self.theme)
|
||||
.map(debug::theme_changed);
|
||||
debug::theme_changed(|| {
|
||||
application::DefaultStyle::palette(&self.theme)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ where
|
|||
{
|
||||
use winit::event_loop::EventLoop;
|
||||
|
||||
let boot_timer = debug::boot_time();
|
||||
let boot_span = debug::boot();
|
||||
|
||||
let event_loop = EventLoop::with_user_event()
|
||||
.build()
|
||||
|
|
@ -153,7 +153,7 @@ where
|
|||
event_receiver,
|
||||
control_sender,
|
||||
init_command,
|
||||
boot_timer,
|
||||
boot_span,
|
||||
));
|
||||
|
||||
let context = task::Context::from_waker(task::noop_waker_ref());
|
||||
|
|
@ -452,7 +452,7 @@ async fn run_instance<A, E, C>(
|
|||
mut event_receiver: mpsc::UnboundedReceiver<Event<A::Message>>,
|
||||
mut control_sender: mpsc::UnboundedSender<Control>,
|
||||
init_command: Command<A::Message>,
|
||||
boot_timer: debug::Timer,
|
||||
boot_span: debug::Span,
|
||||
) where
|
||||
A: Application + 'static,
|
||||
E: Executor + 'static,
|
||||
|
|
@ -524,7 +524,7 @@ async fn run_instance<A, E, C>(
|
|||
);
|
||||
|
||||
runtime.track(application.subscription().into_recipes());
|
||||
boot_timer.finish();
|
||||
boot_span.finish();
|
||||
|
||||
let mut messages = Vec::new();
|
||||
let mut user_events = 0;
|
||||
|
|
@ -636,7 +636,7 @@ async fn run_instance<A, E, C>(
|
|||
&mut messages,
|
||||
);
|
||||
|
||||
let draw_timer = debug::draw_time(id);
|
||||
let draw_span = debug::draw(id);
|
||||
let new_mouse_interaction = ui.draw(
|
||||
&mut window.renderer,
|
||||
window.state.theme(),
|
||||
|
|
@ -645,7 +645,7 @@ async fn run_instance<A, E, C>(
|
|||
},
|
||||
cursor,
|
||||
);
|
||||
draw_timer.finish();
|
||||
draw_span.finish();
|
||||
|
||||
if new_mouse_interaction != window.mouse_interaction {
|
||||
window.raw.set_cursor(
|
||||
|
|
@ -692,7 +692,7 @@ async fn run_instance<A, E, C>(
|
|||
{
|
||||
let logical_size = window.state.logical_size();
|
||||
|
||||
let layout_time = debug::layout_time(id);
|
||||
let layout = debug::layout(id);
|
||||
let ui = user_interfaces
|
||||
.remove(&id)
|
||||
.expect("Remove user interface");
|
||||
|
|
@ -701,9 +701,9 @@ async fn run_instance<A, E, C>(
|
|||
id,
|
||||
ui.relayout(logical_size, &mut window.renderer),
|
||||
);
|
||||
layout_time.finish();
|
||||
layout.finish();
|
||||
|
||||
let draw_time = debug::draw_time(id);
|
||||
let draw = debug::draw(id);
|
||||
let new_mouse_interaction = user_interfaces
|
||||
.get_mut(&id)
|
||||
.expect("Get user interface")
|
||||
|
|
@ -715,7 +715,7 @@ async fn run_instance<A, E, C>(
|
|||
},
|
||||
window.state.cursor(),
|
||||
);
|
||||
draw_time.finish();
|
||||
draw.finish();
|
||||
|
||||
if new_mouse_interaction != window.mouse_interaction
|
||||
{
|
||||
|
|
@ -739,7 +739,7 @@ async fn run_instance<A, E, C>(
|
|||
window.state.viewport_version();
|
||||
}
|
||||
|
||||
let render_time = debug::render_time(id);
|
||||
let present_span = debug::present(id);
|
||||
match compositor.present(
|
||||
&mut window.renderer,
|
||||
&mut window.surface,
|
||||
|
|
@ -747,7 +747,7 @@ async fn run_instance<A, E, C>(
|
|||
window.state.background_color(),
|
||||
) {
|
||||
Ok(()) => {
|
||||
render_time.finish();
|
||||
present_span.finish();
|
||||
|
||||
// TODO: Handle animations!
|
||||
// Maybe we can use `ControlFlow::WaitUntil` for this.
|
||||
|
|
@ -821,7 +821,7 @@ async fn run_instance<A, E, C>(
|
|||
let mut uis_stale = false;
|
||||
|
||||
for (id, window) in window_manager.iter_mut() {
|
||||
let interact_time = debug::interact_time(id);
|
||||
let interact = debug::interact(id);
|
||||
let mut window_events = vec![];
|
||||
|
||||
events.retain(|(window_id, event)| {
|
||||
|
|
@ -864,7 +864,7 @@ async fn run_instance<A, E, C>(
|
|||
{
|
||||
runtime.broadcast(event, status);
|
||||
}
|
||||
interact_time.finish();
|
||||
interact.finish();
|
||||
}
|
||||
|
||||
// TODO mw application update returns which window IDs to update
|
||||
|
|
@ -938,13 +938,13 @@ fn build_user_interface<'a, A: Application>(
|
|||
where
|
||||
A::Theme: DefaultStyle,
|
||||
{
|
||||
let view_timer = debug::view_time(id);
|
||||
let view_span = debug::view(id);
|
||||
let view = application.view(id);
|
||||
view_timer.finish();
|
||||
view_span.finish();
|
||||
|
||||
let layout_timer = debug::layout_time(id);
|
||||
let layout_span = debug::layout(id);
|
||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
||||
layout_timer.finish();
|
||||
layout_span.finish();
|
||||
|
||||
user_interface
|
||||
}
|
||||
|
|
@ -968,9 +968,9 @@ fn update<A: Application, C, E: Executor>(
|
|||
for message in messages.drain(..) {
|
||||
debug::log_message(&message);
|
||||
|
||||
let update_timer = debug::update_time();
|
||||
let update_span = debug::update();
|
||||
let command = runtime.enter(|| application.update(message));
|
||||
update_timer.finish();
|
||||
update_span.finish();
|
||||
|
||||
run_command(
|
||||
application,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue