Skip to main content

Span

Struct Span 

Source
pub struct Span {
    pub t: String,
    pub s: Option<String>,
    pub fx: Option<Fx>,
    pub href: Option<String>,
    pub cite: Vec<Cite>,
}
Expand description

One styled run of text: {t, s?, fx?, href?, cite?}.

Fields§

§t: String

The text.

§s: Option<String>

Space-separated style tokens.

§fx: Option<Fx>

An effect.

§href: Option<String>

A link.

§cite: Vec<Cite>

The sources this run cites; the marker follows the run (an empty t draws the marker alone).

Implementations§

Source§

impl Span

Source

pub fn new(t: impl Into<String>) -> Self

A plain span.

Source

pub fn style(self, token: impl Into<Token>) -> Self

Adds a style token (or several, space-separated).

Examples found in repository?
examples/dashboard.rs (line 409)
408fn mono(v: impl Into<String>) -> Text {
409	ui::span(v).style("mono").into()
410}
411
412impl Dash {
413	/// Sample data.
414	fn new() -> Self {
415		let service = |id, region, version, replicas, health, p95, errors, seed| Service {
416			id,
417			region,
418			version,
419			replicas,
420			health,
421			rps: traffic(120.0, seed),
422			p95,
423			errors,
424		};
425		let deploy = |id: &'static str, service, commit, region, state, done, seed| Deploy {
426			id,
427			service,
428			commit,
429			region,
430			state,
431			done,
432			rps: traffic(40.0, seed),
433		};
434		let incident = |id, title, service, severity, phase, age| Incident {
435			id,
436			title,
437			service,
438			severity,
439			phase,
440			age,
441		};
442		Self {
443			services:   vec![
444				service("api-gateway", "us-east-1", "2.14.0", 6, Health::Healthy, 84.0, 0.1, 3),
445				service("auth", "eu-west-1", "1.9.2", 3, Health::Healthy, 41.0, 0.0, 8),
446				service("search-indexer", "us-west-2", "0.31.4", 2, Health::Degraded, 412.0, 2.7, 13),
447				service("web", "us-east-1", "5.0.1", 8, Health::Healthy, 118.0, 0.2, 5),
448				service("billing", "ap-south-1", "3.3.0", 2, Health::Healthy, 67.0, 0.0, 11),
449				service("notifications", "eu-west-1", "1.2.7", 0, Health::Down, 0.0, 0.0, 2),
450			],
451			deploys:    vec![
452				deploy("api", "api-gateway", "4f2c9e1", "us-east-1", State::Running, 0.42, 3),
453				deploy("auth", "auth", "b71d03a", "eu-west-1", State::Waiting, 0.0, 8),
454				deploy("search", "search-indexer", "09ae5f7", "us-west-2", State::Failed, 0.63, 13),
455				deploy("web", "web", "e3c1a44", "us-east-1", State::Done, 1.0, 5),
456				deploy("billing", "billing", "5d8e2b0", "ap-south-1", State::Waiting, 0.0, 11),
457			],
458			incidents:  vec![
459				incident(
460					"INC-311",
461					"Search results lag behind writes",
462					"search-indexer",
463					Severity::Major,
464					Phase::Open,
465					14 * 60 + 12,
466				),
467				incident(
468					"INC-310",
469					"Notification emails not sent",
470					"notifications",
471					Severity::Critical,
472					Phase::Acknowledged,
473					52 * 60 + 40,
474				),
475				incident(
476					"INC-307",
477					"Slow logins from India",
478					"auth",
479					Severity::Minor,
480					Phase::Resolved,
481					5 * 3600 + 18 * 60,
482				),
483			],
484			page:       Page::Services,
485			filter:     "all".into(),
486			selected:   [Some("api-gateway"), Some("api"), Some("INC-311")],
487			confirming: None,
488			note:       String::new(),
489			ticks:      0,
490		}
491	}
492
493	/// The deploys the filter shows.
494	fn shown_deploys(&self) -> Vec<&Deploy> {
495		self
496			.deploys
497			.iter()
498			.filter(|d| self.filter == "all" || matches!(d.state, State::Waiting | State::Failed))
499			.collect()
500	}
501
502	/// The ids of the rows `page` shows, in order.
503	fn ids(&self, page: Page) -> Vec<&'static str> {
504		match page {
505			Page::Services => self.services.iter().map(|s| s.id).collect(),
506			Page::Deploys => self.shown_deploys().iter().map(|d| d.id).collect(),
507			Page::Incidents => self.incidents.iter().map(|i| i.id).collect(),
508		}
509	}
510
511	/// Moves `page`'s selection by `by` rows; `0` keeps a selection still
512	/// shown and otherwise picks the first row.
513	fn pick(&mut self, page: Page, by: isize) {
514		let ids = self.ids(page);
515		let slot = &mut self.selected[page.index()];
516		let Some(last) = ids.len().checked_sub(1) else {
517			*slot = None;
518			return;
519		};
520		let at = slot
521			.and_then(|s| ids.iter().position(|id| *id == s))
522			.map_or(0, |i| i.saturating_add_signed(by).min(last));
523		*slot = Some(ids[at]);
524	}
525
526	/// Selects row `id` of `page` if it is there.
527	fn select(&mut self, page: Page, id: &str) {
528		self.selected[page.index()] = self.ids(page).into_iter().find(|s| *s == id);
529	}
530
531	/// The destructive action on row `id` of `page`.
532	fn risk(&self, page: Page, id: &str) -> Option<Risk> {
533		match page {
534			Page::Services => self.services.iter().find(|s| s.id == id).map(Service::risk),
535			Page::Deploys => self.deploys.iter().find(|d| d.id == id).map(Deploy::risk),
536			Page::Incidents => self
537				.incidents
538				.iter()
539				.find(|i| i.id == id)
540				.map(Incident::risk),
541		}
542	}
543
544	/// Advances the rollouts, the traffic and the clocks one tick.
545	fn tick(&mut self) {
546		self.ticks += 1;
547		let ticks = self.ticks;
548		for (s, i) in self.services.iter_mut().zip(0u32..) {
549			let swing = f64::from((ticks * 5 + i * 11) % 17);
550			s.rps.remove(0);
551			if s.health == Health::Down {
552				s.rps.push(0.0);
553				s.p95 = 0.0;
554			} else {
555				s.rps.push(110.0 + swing * 3.0);
556				let base = if s.health == Health::Degraded {
557					380.0
558				} else {
559					60.0
560				};
561				s.p95 = base + swing * 4.0;
562			}
563		}
564		for (d, i) in self.deploys.iter_mut().zip(0u32..) {
565			let swing = f64::from((ticks * 5 + i * 11) % 17);
566			d.rps.remove(0);
567			d.rps.push(38.0 + swing);
568			if d.state == State::Running {
569				d.done = (d.done + 0.04).min(1.0);
570				if d.done >= 1.0 {
571					d.state = State::Done;
572				}
573			}
574		}
575		for inc in &mut self.incidents {
576			if inc.phase != Phase::Resolved {
577				inc.age += TICK.as_secs();
578			}
579		}
580	}
581
582	/// Applies a message from the view.
583	fn update(&mut self, msg: Msg) {
584		match msg {
585			Msg::Page(id) => {
586				if let Some(page) = Page::from_id(&id) {
587					self.page = page;
588				}
589			},
590			Msg::Filter(filter) => {
591				self.filter = filter;
592				self.pick(Page::Deploys, 0);
593			},
594			Msg::Refresh => {
595				self.tick();
596				self.note = "Refreshed".into();
597			},
598			Msg::Select(page, id) => self.select(page, &id),
599			Msg::Open(page, id) => {
600				self.select(page, &id);
601				self.note = format!("Opened {id}");
602			},
603			Msg::Act(page, id) => {
604				let done = match page {
605					Page::Services => self
606						.services
607						.iter_mut()
608						.find(|s| s.id == id)
609						.map(Service::act),
610					Page::Deploys => self
611						.deploys
612						.iter_mut()
613						.find(|d| d.id == id)
614						.and_then(Deploy::act),
615					Page::Incidents => self
616						.incidents
617						.iter_mut()
618						.find(|i| i.id == id)
619						.and_then(Incident::act),
620				};
621				if let Some(done) = done {
622					self.note = format!("{done} {id}");
623				}
624				self.pick(page, 0);
625			},
626			Msg::Ask(page, id) => {
627				self.confirming = self
628					.ids(page)
629					.into_iter()
630					.find(|s| *s == id)
631					.filter(|_| self.risk(page, &id).is_some_and(|r| r.blocked.is_none()))
632					.map(|s| (page, s));
633			},
634			Msg::Confirm => {
635				let Some((page, id)) = self.confirming.take() else {
636					return;
637				};
638				let Some(risk) = self.risk(page, id) else {
639					return;
640				};
641				match page {
642					Page::Services => {
643						if let Some(s) = self.services.iter_mut().find(|s| s.id == id) {
644							s.replicas = 0;
645							s.health = Health::Down;
646						}
647					},
648					Page::Deploys => self.deploys.retain(|d| d.id != id),
649					Page::Incidents => self.incidents.retain(|i| i.id != id),
650				}
651				self.note = format!("{} {id}", risk.done);
652				self.pick(page, 0);
653			},
654			Msg::Keep => self.confirming = None,
655		}
656	}
657
658	/// Runs the selected row's primary action (key `a`).
659	fn act_selected(&mut self) {
660		if let Some(id) = self.selected[self.page.index()] {
661			self.update(Msg::Act(self.page, id.into()));
662		}
663	}
664
665	/// The whole screen. `plain` stacks the detail under the table instead
666	/// of beside it, for the plain-text fallback.
667	fn view(&self, plain: bool) -> View<Msg> {
668		let main = nodes![self.head(), self.stats().key("stats"), self.nav(), self.body(plain)];
669		let mut dock: Vec<Node<Msg>> = Vec::new();
670		if let Some((page, id)) = self.confirming
671			&& let Some(risk) = self.risk(page, id)
672		{
673			dock.push(confirm(&risk).into());
674		}
675		dock.push(self.legend().into());
676		View::new().main(main).dock(dock)
677	}
678
679	/// The head row: the title and muted meta, a status badge and Refresh.
680	fn head(&self) -> ui::Row<Msg> {
681		let title = ui::text(spans![
682			ui::span("Fleet").style("title"),
683			" ",
684			ui::span(format!(
685				"production · {} services · up {}",
686				self.services.len(),
687				ago(UPTIME + u64::from(self.ticks))
688			))
689			.style("muted"),
690		])
691		.key("title");
692		let worst = self
693			.services
694			.iter()
695			.map(|s| s.health)
696			.max_by_key(|h| match h {
697				Health::Healthy => 0,
698				Health::Degraded => 1,
699				Health::Down => 2,
700			})
701			.unwrap_or(Health::Healthy);
702		let status = match worst {
703			Health::Healthy => ui::badge("Operational").tone(Tone::Success),
704			Health::Degraded => ui::badge("Degraded").tone(Tone::Warning),
705			Health::Down => ui::badge("Partial outage").tone(Tone::Error),
706		};
707		let refresh = ui::button("Refresh")
708			.key("refresh")
709			.icon("repeat")
710			.keys(["r"])
711			.on_click(Msg::Refresh);
712		ui::row()
713			.key("head")
714			.justify("between")
715			.align("center")
716			.child(title)
717			.child(
718				ui::row()
719					.key("end")
720					.gap("sm")
721					.align("center")
722					.children(nodes![status.key("status"), refresh]),
723			)
724	}
725
726	/// The stats strip: at most four tiles, directly on the page.
727	fn stats(&self) -> ui::Stats<Msg> {
728		let total = self.services.len();
729		let healthy = self
730			.services
731			.iter()
732			.filter(|s| s.health == Health::Healthy)
733			.count();
734		let deploys = |state| self.deploys.iter().filter(|d| d.state == state).count();
735		let open = self
736			.incidents
737			.iter()
738			.filter(|i| i.phase != Phase::Resolved)
739			.count();
740		let unacked = self
741			.incidents
742			.iter()
743			.filter(|i| i.phase == Phase::Open)
744			.count();
745		let rps: f64 = self.services.iter().filter_map(|s| s.rps.last()).sum();
746		let mut services = StatItem::new("Healthy", format!("{healthy}/{total}")).sub("services");
747		if healthy < total {
748			services = services.tone(Tone::Warning);
749		}
750		let mut incidents =
751			StatItem::new("Open incidents", open.to_string()).sub(format!("{unacked} unacknowledged"));
752		if unacked > 0 {
753			incidents = incidents.tone(Tone::Error);
754		}
755		ui::stats([
756			services,
757			StatItem::new("Rolling out", deploys(State::Running).to_string())
758				.sub(format!("{} need approval", deploys(State::Waiting))),
759			incidents,
760			StatItem::new("Traffic", format!("{rps:.0}")).sub("req/s"),
761		])
762	}
763
764	/// The tabs: one per view, with muted counts.
765	fn nav(&self) -> ui::Tabs<Msg> {
766		let count = |n: usize| ui::span(n.to_string()).style("muted");
767		let open = self
768			.incidents
769			.iter()
770			.filter(|i| i.phase != Phase::Resolved)
771			.count();
772		ui::tabs()
773			.key("nav")
774			.active(self.page.id())
775			.tab("services", spans!["Services ", count(self.services.len())])
776			.tab("deploys", spans!["Deploys ", count(self.deploys.len())])
777			.tab("incidents", spans!["Incidents ", count(open)])
778			.on_select(|id| Msg::Page(id.to_owned()))
779	}
780
781	/// The active view: its table beside the selected row's detail card
782	/// (under it when `plain`).
783	fn body(&self, plain: bool) -> Node<Msg> {
784		let page = self.page;
785		let selected = self.selected[page.index()];
786		let (list, detail) = match page {
787			Page::Services => (
788				nodes![self.services_table()],
789				selected
790					.and_then(|id| self.services.iter().find(|s| s.id == id))
791					.map(service_card),
792			),
793			Page::Deploys => (
794				nodes![self.deploys_bar(), self.deploys_table()],
795				selected
796					.and_then(|id| self.deploys.iter().find(|d| d.id == id))
797					.map(deploy_card),
798			),
799			Page::Incidents => (
800				nodes![self.incidents_table()],
801				selected
802					.and_then(|id| self.incidents.iter().find(|i| i.id == id))
803					.map(incident_card),
804			),
805		};
806		let mut parts: Vec<Node<Msg>> = nodes![
807			ui::col()
808				.key("list")
809				.gap("sm")
810				.grow(1.0)
811				.basis(0.0)
812				.children(list)
813		];
814		if let Some(card) = detail {
815			parts.push(
816				card
817					.key("detail")
818					.min(Bound::w(Extent::Ch(44.0)))
819					.max(Bound::w(Extent::Ch(56.0)))
820					.into(),
821			);
822		}
823		if plain {
824			ui::col().key(page.id()).gap("md").children(parts).into()
825		} else {
826			ui::row()
827				.key(page.id())
828				.align("stretch")
829				.gap("lg")
830				.children(parts)
831				.into()
832		}
833	}
834
835	/// A selectable table of `page` with its handlers and selection.
836	fn table(&self, page: Page, empty: &str) -> ui::Table<Msg> {
837		let mut table = ui::table()
838			.key("table")
839			.selectable(true)
840			.empty(empty)
841			.on_select(move |id| Msg::Select(page, id.to_owned()))
842			.on_activate(move |id| Msg::Open(page, id.to_owned()));
843		if let Some(id) = self.selected[page.index()] {
844			table = table.selected(id);
845		}
846		table
847	}
848
849	/// The services table.
850	fn services_table(&self) -> ui::Table<Msg> {
851		let mut table = self
852			.table(Page::Services, "No services yet")
853			.col(Column::new("name", "Service").grow(1.0).priority(6.0))
854			.col(Column::new("region", "Region").priority(3.0))
855			.col(Column::new("version", "Version").mono(true).priority(2.0))
856			.col(Column::new("traffic", "Traffic").priority(1.0))
857			.col(
858				Column::new("rps", "req/s")
859					.align(TextAlign::End)
860					.mono(true)
861					.priority(4.0),
862			)
863			.col(
864				Column::new("p95", "p95")
865					.align(TextAlign::End)
866					.mono(true)
867					.priority(4.0),
868			)
869			.col(
870				Column::new("errors", "Errors")
871					.align(TextAlign::End)
872					.mono(true)
873					.priority(4.0),
874			)
875			.col(Column::new("health", "Health").priority(5.0));
876		for s in &self.services {
877			let (label, tone) = s.health.look();
878			let mut errors = TextCell::new(format!("{:.1}%", s.errors));
879			if s.errors >= 1.0 {
880				errors = errors.tone(Tone::Error);
881			}
882			table = table.row(
883				TableRow::new(s.id)
884					.cell("name", TextCell::new(s.id).dot(tone.clone()))
885					.cell("region", s.region)
886					.cell("version", s.version)
887					.cell("traffic", SparkCell::new(s.rps.clone()))
888					.cell("rps", format!("{:.0}", s.rps.last().copied().unwrap_or_default()))
889					.cell("p95", format!("{:.0} ms", s.p95))
890					.cell("errors", errors)
891					.cell("health", BadgeSpec::new(label).tone(tone)),
892			);
893		}
894		table
895	}
896
897	/// The deploys toolbar: a muted description and the filter.
898	fn deploys_bar(&self) -> ui::Row<Msg> {
899		let attention = self
900			.deploys
901			.iter()
902			.filter(|d| matches!(d.state, State::Waiting | State::Failed))
903			.count();
904		ui::row()
905			.key("bar")
906			.justify("between")
907			.align("center")
908			.child(
909				ui::text(ui::span("Rollouts to production, newest first").style("muted")).key("about"),
910			)
911			.child(
912				ui::tabs()
913					.key("filter")
914					.variant("segmented")
915					.active(self.filter.clone())
916					.tab("all", "All")
917					.tab("attention", spans![
918						"Needs you ",
919						ui::span(attention.to_string()).style("muted")
920					])
921					.on_select(|id| Msg::Filter(id.to_owned())),
922			)
923	}
924
925	/// The deploys table.
926	fn deploys_table(&self) -> ui::Table<Msg> {
927		let mut table = self
928			.table(Page::Deploys, "Nothing needs you right now")
929			.col(Column::new("service", "Service").grow(1.0).priority(6.0))
930			.col(Column::new("commit", "Commit").mono(true).priority(3.0))
931			.col(Column::new("region", "Region").priority(2.0))
932			.col(Column::new("traffic", "Traffic").priority(1.0))
933			.col(Column::new("rollout", "Rollout").priority(1.0))
934			.col(Column::new("state", "State").priority(5.0));
935		for d in self.shown_deploys() {
936			let (label, tone) = d.state.look();
937			table = table.row(
938				TableRow::new(d.id)
939					.cell("service", TextCell::new(d.service).dot(tone.clone()))
940					.cell("commit", d.commit)
941					.cell("region", d.region)
942					.cell("traffic", SparkCell::new(d.rps.clone()))
943					.cell("rollout", MeterCell {
944						value: Some(d.done),
945						title: Some(format!("{:.0}%", d.done * 100.0)),
946						..MeterCell::default()
947					})
948					.cell("state", BadgeSpec::new(label).tone(tone)),
949			);
950		}
951		table
952	}
953
954	/// The incidents table.
955	fn incidents_table(&self) -> ui::Table<Msg> {
956		let mut table = self
957			.table(Page::Incidents, "No incidents. All quiet.")
958			.col(Column::new("title", "Incident").grow(1.0).priority(6.0))
959			.col(Column::new("id", "Id").mono(true).priority(2.0))
960			.col(Column::new("service", "Service").priority(3.0))
961			.col(Column::new("severity", "Severity").priority(4.0))
962			.col(
963				Column::new("age", "Open for")
964					.align(TextAlign::End)
965					.mono(true)
966					.priority(4.0),
967			)
968			.col(Column::new("phase", "State").priority(5.0));
969		for i in &self.incidents {
970			let (sev, sev_tone) = i.severity.look();
971			let (phase, phase_tone) = i.phase.look();
972			table = table.row(
973				TableRow::new(i.id)
974					.cell("title", TextCell::new(i.title).dot(sev_tone.clone()))
975					.cell("id", i.id)
976					.cell("service", i.service)
977					.cell("severity", BadgeSpec::new(sev).tone(sev_tone))
978					.cell("age", ago(i.age))
979					.cell("phase", BadgeSpec::new(phase).tone(phase_tone)),
980			);
981		}
982		table
983	}
984
985	/// The key legend.
986	fn legend(&self) -> ui::Row<Msg> {
987		let key = |k: &str| ui::span(k).style("key");
988		let muted = |t: &str| ui::span(t).style("muted");
989		let keys = if self.confirming.is_some() {
990			spans![key("enter"), muted(" confirm  "), key("esc"), muted(" back")]
991		} else {
992			spans![
993				key("tab"),
994				muted(" views  "),
995				key("j"),
996				key("k"),
997				muted(" move  "),
998				key("enter"),
999				muted(" open  "),
1000				key("a"),
1001				muted(" action  "),
1002				key("r"),
1003				muted(" refresh  "),
1004				key("q"),
1005				muted(" quit"),
1006			]
1007		};
1008		let note = if self.note.is_empty() {
1009			"Up to date"
1010		} else {
1011			self.note.as_str()
1012		};
1013		ui::row()
1014			.key("legend")
1015			.justify("between")
1016			.align("center")
1017			.child(ui::text(keys).key("keys"))
1018			.child(ui::text(muted(note)).key("note"))
1019	}
1020}
1021
1022/// A detail card: the head with the primary action at its end, the `kv` and
1023/// the `danger` trigger.
1024fn detail(
1025	page: Page,
1026	id: &'static str,
1027	meta: impl Into<Text>,
1028	kv: ui::Kv<Msg>,
1029	action: Option<&'static str>,
1030	risk: &Risk,
1031) -> ui::Card<Msg> {
1032	let mut card = ui::card().head(id).meta(meta);
1033	if let Some(label) = action {
1034		card = card.end(
1035			ui::button(label)
1036				.key("act")
1037				.variant("primary")
1038				.keys(["a"])
1039				.on_click(Msg::Act(page, id.into())),
1040		);
1041	}
1042	let mut trigger = ui::button(risk.button)
1043		.key("risk")
1044		.variant("danger")
1045		.on_click(Msg::Ask(page, id.into()));
1046	if let Some(why) = risk.blocked {
1047		trigger = trigger.disabled(why);
1048	}
1049	card
1050		.child(kv.key("kv"))
1051		.child(ui::row().key("bar").child(trigger))
1052}
1053
1054/// The selected service's detail card.
1055fn service_card(s: &Service) -> ui::Card<Msg> {
1056	let (label, _) = s.health.look();
1057	let rps = s.rps.last().copied().unwrap_or_default();
1058	let kv = ui::kv()
1059		.item("Health", ui::span(label).style("strong"))
1060		.item("Version", mono(s.version))
1061		.item("Replicas", mono(s.replicas.to_string()))
1062		.item("Traffic", mono(format!("{rps:.0} req/s")))
1063		.item("p95", mono(format!("{:.0} ms", s.p95)))
1064		.item("Errors", mono(format!("{:.1}%", s.errors)));
1065	detail(Page::Services, s.id, s.region, kv, Some(s.action()), &s.risk())
1066}
1067
1068/// The selected deploy's detail card.
1069fn deploy_card(d: &Deploy) -> ui::Card<Msg> {
1070	let (label, _) = d.state.look();
1071	let rps = d.rps.last().copied().unwrap_or_default();
1072	let kv = ui::kv()
1073		.item("State", ui::span(label).style("strong"))
1074		.item("Service", d.service)
1075		.item("Commit", mono(d.commit))
1076		.item("Rollout", mono(format!("{:.0}%", d.done * 100.0)))
1077		.item("Traffic", mono(format!("{rps:.0} req/s")));
1078	detail(Page::Deploys, d.id, d.region, kv, d.action(), &d.risk())
1079}
1080
1081/// The selected incident's detail card.
1082fn incident_card(i: &Incident) -> ui::Card<Msg> {
1083	let (phase, _) = i.phase.look();
1084	let (sev, _) = i.severity.look();
1085	let kv = ui::kv()
1086		.item("State", ui::span(phase).style("strong"))
1087		.item("What", i.title)
1088		.item("Service", i.service)
1089		.item("Severity", sev)
1090		.item("Open for", mono(ago(i.age)));
1091	detail(Page::Incidents, i.id, i.service, kv, i.action(), &i.risk())
1092}
Source

pub fn fx(self, fx: impl Into<Fx>) -> Self

Sets the effect.

Source

pub fn href(self, href: impl Into<String>) -> Self

Makes the span a link.

Source

pub fn cite(self, cite: Cite) -> Self

Cites a source after the run.

Trait Implementations§

Source§

impl Clone for Span

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Span

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Span

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Eq for Span

Source§

impl From<&str> for Span

Source§

fn from(t: &str) -> Self

Converts to this type from the input type.
Source§

impl From<Span> for Text

Source§

fn from(span: Span) -> Self

Converts to this type from the input type.
Source§

impl<M> From<Span> for Slot<M>

Source§

fn from(s: Span) -> Self

Converts to this type from the input type.
Source§

impl From<String> for Span

Source§

fn from(t: String) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Span

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for Span

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Span

Auto Trait Implementations§

§

impl Freeze for Span

§

impl RefUnwindSafe for Span

§

impl Send for Span

§

impl Sync for Span

§

impl Unpin for Span

§

impl UnsafeUnpin for Span

§

impl UnwindSafe for Span

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more