topcoat_runtime/
shard_scope.rs1use std::{
2 pin::Pin,
3 task::{Context, Poll, ready},
4};
5
6use pin_project_lite::pin_project;
7use topcoat_core::{context::Cx, error::Result, identity::Identity};
8use topcoat_view::{NodeViewParts, PartsWriter, View, ViewFirst, ViewSwap, internal::Builder};
9
10use crate::Js;
11
12pin_project! {
13 pub struct ShardScope<'cx, V> {
20 cx: &'cx Cx,
21 identity: Identity,
26 url: &'static str,
28 exprs: Vec<Js>,
29 #[pin]
30 view: V,
31 }
32}
33
34impl<'cx, V> ShardScope<'cx, V> {
35 #[inline]
36 #[must_use]
37 pub fn new(
38 cx: &'cx Cx,
39 identity: Identity,
40 url: &'static str,
41 exprs: Vec<Js>,
42 view: V,
43 ) -> Self {
44 Self {
45 cx,
46 identity,
47 url,
48 exprs,
49 view,
50 }
51 }
52}
53
54impl<V: View> View for ShardScope<'_, V> {
55 fn poll_first(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<ViewFirst>> {
56 let this = self.project();
57 let first = ready!(this.view.poll_first(cx))?;
58 let identity = serde_json::to_string(&this.identity.to_string()).unwrap();
59 let content = Builder::block(this.cx, |builder| {
60 builder.node(StartMarker {
61 url: this.url,
62 identity: &identity,
63 exprs: this.exprs,
64 });
65 builder.view(first.content);
66 builder.node(EndMarker { identity });
67 });
68 Poll::Ready(Ok(ViewFirst {
69 content,
70 live: first.live,
71 }))
72 }
73
74 fn poll_swap(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<Option<ViewSwap>>> {
75 self.project().view.poll_swap(cx)
76 }
77}
78
79struct StartMarker<'a> {
89 url: &'static str,
90 identity: &'a str,
92 exprs: &'a [Js],
93}
94
95impl NodeViewParts for StartMarker<'_> {
96 fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
97 parts.push_comment(|comment| {
99 comment
100 .push_promoted_str_unescaped(&"::topcoat::shard::start(")
101 .push_string_unescaped(serde_json::to_string(self.url).unwrap())
102 .push_promoted_str_unescaped(&", ")
103 .push_string_unescaped(self.identity.to_owned())
104 .push_promoted_str_unescaped(&", [");
105 let last = self.exprs.len().saturating_sub(1);
106 for (index, expr) in self.exprs.iter().enumerate() {
107 comment.push_promoted_str_unescaped(&"\"");
108 expr.write(comment);
109 comment.push_promoted_str_unescaped(&"\"");
110 if index != last {
111 comment.push_promoted_str_unescaped(&", ");
112 }
113 }
114 comment.push_promoted_str_unescaped(&"])");
115 });
116 }
117}
118
119struct EndMarker {
121 identity: String,
123}
124
125impl NodeViewParts for EndMarker {
126 fn into_view_parts(self, _cx: &Cx, parts: &mut PartsWriter<'_>) {
127 parts.push_comment(|comment| {
129 comment
130 .push_promoted_str_unescaped(&"::topcoat::shard::end(")
131 .push_string_unescaped(self.identity)
132 .push_promoted_str_unescaped(&")");
133 });
134 }
135}