Skip to content

Commit 14062fa

Browse files
authored
Merge branch 'master' into feat/forc-mcp-auth
2 parents 97bf9ea + c7ff312 commit 14062fa

File tree

7 files changed

+116
-58
lines changed

7 files changed

+116
-58
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

forc-plugins/forc-doc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ horrorshow.workspace = true
1919
include_dir.workspace = true
2020
minifier.workspace = true
2121
opener.workspace = true
22+
rayon.workspace = true
2223
serde.workspace = true
2324
serde_json.workspace = true
2425
sway-ast.workspace = true

forc-plugins/forc-doc/src/doc/descriptor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ trait RequiredMethods {
2727
impl RequiredMethods for Vec<DeclRefTraitFn> {
2828
fn to_methods(&self, decl_engine: &DeclEngine) -> Vec<TyTraitFn> {
2929
self.iter()
30-
.map(|decl_ref| (*decl_engine.get_trait_fn(decl_ref)).clone())
30+
.map(|decl_ref| decl_engine.get_trait_fn(decl_ref).as_ref().clone())
3131
.collect()
3232
}
3333
}
@@ -371,7 +371,7 @@ impl Descriptor {
371371
module_info,
372372
ty: DocumentableType::Primitive(type_info.clone()),
373373
item_name: item_name.clone(),
374-
code_str: item_name.clone().to_string(),
374+
code_str: item_name.to_string(),
375375
attrs_opt: attrs_opt.clone(),
376376
item_context: Default::default(),
377377
},

forc-plugins/forc-doc/src/doc/mod.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
},
1515
};
1616
use anyhow::Result;
17+
use rayon::prelude::*;
1718
use std::{
1819
collections::HashMap,
1920
ops::{Deref, DerefMut},
@@ -80,14 +81,24 @@ impl Documentation {
8081
.collect::<HashMap<BaseIdent, ModuleInfo>>();
8182

8283
// Add one documentation page for each primitive type that has an implementation.
83-
for (impl_trait, module_info) in impl_traits.iter() {
84-
let impl_for_type = engines.te().get(impl_trait.implementing_for.type_id());
85-
if let Ok(Descriptor::Documentable(doc)) =
86-
Descriptor::from_type_info(impl_for_type.as_ref(), engines, module_info.clone())
87-
{
88-
if !docs.contains(&doc) {
89-
docs.push(doc);
84+
let primitive_docs: Vec<_> = impl_traits
85+
.par_iter()
86+
.filter_map(|(impl_trait, module_info)| {
87+
let impl_for_type = engines.te().get(impl_trait.implementing_for.type_id());
88+
if let Ok(Descriptor::Documentable(doc)) =
89+
Descriptor::from_type_info(impl_for_type.as_ref(), engines, module_info.clone())
90+
{
91+
Some(doc)
92+
} else {
93+
None
9094
}
95+
})
96+
.collect();
97+
98+
// Add unique primitive docs
99+
for doc in primitive_docs {
100+
if !docs.contains(&doc) {
101+
docs.push(doc);
91102
}
92103
}
93104

@@ -103,7 +114,7 @@ impl Documentation {
103114
DocumentableType::Declared(TyDecl::StructDecl(_))
104115
| DocumentableType::Declared(TyDecl::EnumDecl(_))
105116
| DocumentableType::Primitive(_) => {
106-
let item_name = doc.item_header.item_name.clone();
117+
let item_name = &doc.item_header.item_name;
107118
for (impl_trait, _) in impl_traits.iter_mut() {
108119
// Check if this implementation is for this struct/enum.
109120
if item_name.as_str()
@@ -157,13 +168,23 @@ impl Documentation {
157168
document_private_items: bool,
158169
experimental: ExperimentalFeatures,
159170
) -> Result<()> {
160-
for ast_node in &ty_module.all_nodes {
161-
if let TyAstNodeContent::Declaration(ref decl) = ast_node.content {
171+
let results: Result<Vec<_>, anyhow::Error> = ty_module
172+
.all_nodes
173+
.par_iter()
174+
.filter_map(|ast_node| {
175+
if let TyAstNodeContent::Declaration(ref decl) = ast_node.content {
176+
Some(decl)
177+
} else {
178+
None
179+
}
180+
})
181+
.map(|decl| {
162182
if let TyDecl::ImplSelfOrTrait(impl_trait) = decl {
163-
impl_traits.push((
183+
let impl_data = (
164184
(*decl_engine.get_impl_self_or_trait(&impl_trait.decl_id)).clone(),
165185
module_info.clone(),
166-
));
186+
);
187+
Ok((Some(impl_data), None))
167188
} else {
168189
let desc = Descriptor::from_typed_decl(
169190
decl_engine,
@@ -173,10 +194,21 @@ impl Documentation {
173194
experimental,
174195
)?;
175196

176-
if let Descriptor::Documentable(doc) = desc {
177-
docs.push(doc);
178-
}
197+
let doc = match desc {
198+
Descriptor::Documentable(doc) => Some(doc),
199+
Descriptor::NonDocumentable => None,
200+
};
201+
Ok((None, doc))
179202
}
203+
})
204+
.collect();
205+
206+
for (impl_trait_opt, doc_opt) in results? {
207+
if let Some(impl_trait) = impl_trait_opt {
208+
impl_traits.push(impl_trait);
209+
}
210+
if let Some(doc) = doc_opt {
211+
docs.push(doc);
180212
}
181213
}
182214

forc-plugins/forc-doc/src/render/item/components.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ use sway_types::BaseIdent;
1616

1717
use super::documentable_type::DocumentableType;
1818

19+
// Asset file names to avoid repeated string formatting
20+
const SWAY_LOGO_FILE: &str = "sway-logo.svg";
21+
const NORMALIZE_CSS_FILE: &str = "normalize.css";
22+
const SWAYDOC_CSS_FILE: &str = "swaydoc.css";
23+
const AYU_CSS_FILE: &str = "ayu.css";
24+
const AYU_MIN_CSS_FILE: &str = "ayu.min.css";
25+
1926
/// All necessary components to render the header portion of
2027
/// the item html doc.
2128
#[derive(Clone, Debug)]
@@ -33,15 +40,16 @@ impl Renderable for ItemHeader {
3340
item_name,
3441
} = self;
3542

36-
let favicon =
37-
module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/sway-logo.svg"));
38-
let normalize =
39-
module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/normalize.css"));
40-
let swaydoc =
41-
module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/swaydoc.css"));
42-
let ayu = module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/ayu.css"));
43-
let ayu_hjs =
44-
module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/ayu.min.css"));
43+
let favicon = module_info
44+
.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{SWAY_LOGO_FILE}"));
45+
let normalize = module_info
46+
.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{NORMALIZE_CSS_FILE}"));
47+
let swaydoc = module_info
48+
.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{SWAYDOC_CSS_FILE}"));
49+
let ayu =
50+
module_info.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{AYU_CSS_FILE}"));
51+
let ayu_hjs = module_info
52+
.to_html_shorthand_path_string(&format!("{ASSETS_DIR_NAME}/{AYU_MIN_CSS_FILE}"));
4553

4654
Ok(box_html! {
4755
head {

forc-plugins/forc-doc/src/render/item/type_anchor.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,16 @@ pub(crate) fn render_type_anchor(
6767
let enum_decl = render_plan.engines.de().get_enum(&decl_id);
6868
if !render_plan.document_private_items && enum_decl.visibility.is_private() {
6969
Ok(box_html! {
70-
: enum_decl.name().clone().as_str();
70+
: enum_decl.name().as_str();
7171
})
7272
} else {
7373
let module_info = ModuleInfo::from_call_path(&enum_decl.call_path);
74-
let file_name = format!("enum.{}.html", enum_decl.name().clone().as_str());
74+
let file_name = format!("enum.{}.html", enum_decl.name().as_str());
7575
let href =
7676
module_info.file_path_from_location(&file_name, current_module_info, false)?;
7777
Ok(box_html! {
7878
a(class="enum", href=href) {
79-
: enum_decl.name().clone().as_str();
79+
: enum_decl.name().as_str();
8080
}
8181
})
8282
}
@@ -85,16 +85,16 @@ pub(crate) fn render_type_anchor(
8585
let struct_decl = render_plan.engines.de().get_struct(&decl_id);
8686
if !render_plan.document_private_items && struct_decl.visibility.is_private() {
8787
Ok(box_html! {
88-
: struct_decl.name().clone().as_str();
88+
: struct_decl.name().as_str();
8989
})
9090
} else {
9191
let module_info = ModuleInfo::from_call_path(&struct_decl.call_path);
92-
let file_name = format!("struct.{}.html", struct_decl.name().clone().as_str());
92+
let file_name = format!("struct.{}.html", struct_decl.name().as_str());
9393
let href =
9494
module_info.file_path_from_location(&file_name, current_module_info, false)?;
9595
Ok(box_html! {
9696
a(class="struct", href=href) {
97-
: struct_decl.name().clone().as_str();
97+
: struct_decl.name().as_str();
9898
}
9999
})
100100
}

forc-plugins/forc-doc/src/render/mod.rs

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::{
1414
};
1515
use anyhow::Result;
1616
use horrorshow::{box_html, helper::doctype, html, prelude::*};
17+
use rayon::prelude::*;
1718
use std::{
1819
collections::BTreeMap,
1920
ops::{Deref, DerefMut},
@@ -33,6 +34,10 @@ pub const ALL_DOC_FILENAME: &str = "all.html";
3334
pub const INDEX_FILENAME: &str = "index.html";
3435
pub const IDENTITY: &str = "#";
3536

37+
type DocLinkMap = BTreeMap<BlockTitle, Vec<DocLink>>;
38+
type ModuleMap = BTreeMap<ModulePrefixes, DocLinkMap>;
39+
type RenderResult = (RenderedDocument, ModuleMap, DocLinks);
40+
3641
/// Something that can be rendered to HTML.
3742
pub(crate) trait Renderable {
3843
fn render(self, render_plan: RenderPlan) -> Result<Box<dyn RenderBox>>;
@@ -90,19 +95,36 @@ impl RenderedDocumentation {
9095
style: DocStyle::AllDoc(program_kind.as_title_str().to_string()),
9196
links: BTreeMap::default(),
9297
};
93-
let mut module_map: BTreeMap<ModulePrefixes, BTreeMap<BlockTitle, Vec<DocLink>>> =
94-
BTreeMap::new();
95-
for doc in raw_docs.0 {
96-
rendered_docs
97-
.0
98-
.push(RenderedDocument::from_doc(&doc, render_plan.clone())?);
98+
// Parallel document rendering
99+
let rendered_results: Result<Vec<RenderResult>, anyhow::Error> = raw_docs
100+
.0
101+
.par_iter()
102+
.map(|doc| {
103+
let rendered_doc = RenderedDocument::from_doc(doc, render_plan.clone())?;
104+
let mut local_module_map = ModuleMap::new();
105+
let mut local_all_docs = DocLinks {
106+
style: DocStyle::AllDoc(program_kind.as_title_str().to_string()),
107+
links: BTreeMap::default(),
108+
};
109+
110+
populate_decls(doc, &mut local_module_map);
111+
populate_modules(doc, &mut local_module_map);
112+
populate_doc_links(doc, &mut local_all_docs.links);
113+
114+
Ok((rendered_doc, local_module_map, local_all_docs))
115+
})
116+
.collect();
99117

100-
// Here we gather all of the `doc_links` based on which module they belong to.
101-
populate_decls(&doc, &mut module_map);
102-
// Create links to child modules.
103-
populate_modules(&doc, &mut module_map);
104-
// Above we check for the module a link belongs to, here we want _all_ links so the check is much more shallow.
105-
populate_all_doc(&doc, &mut all_docs);
118+
// Merge results sequentially
119+
let mut module_map = ModuleMap::new();
120+
for (rendered_doc, local_module_map, local_all_docs) in rendered_results? {
121+
rendered_docs.0.push(rendered_doc);
122+
123+
for (key, value) in local_module_map {
124+
module_map.entry(key).or_default().extend(value);
125+
}
126+
127+
all_docs.links.extend(local_all_docs.links);
106128
}
107129

108130
// ProjectIndex
@@ -199,7 +221,8 @@ impl DerefMut for RenderedDocumentation {
199221
}
200222
}
201223

202-
fn populate_doc_links(doc: &Document, doc_links: &mut BTreeMap<BlockTitle, Vec<DocLink>>) {
224+
/// Adds a document's link to the appropriate category in the doc links map.
225+
fn populate_doc_links(doc: &Document, doc_links: &mut DocLinkMap) {
203226
let key = doc.item_body.ty.as_block_title();
204227
match doc_links.get_mut(&key) {
205228
Some(links) => links.push(doc.link()),
@@ -208,23 +231,19 @@ fn populate_doc_links(doc: &Document, doc_links: &mut BTreeMap<BlockTitle, Vec<D
208231
}
209232
}
210233
}
211-
fn populate_decls(
212-
doc: &Document,
213-
module_map: &mut BTreeMap<ModulePrefixes, BTreeMap<BlockTitle, Vec<DocLink>>>,
214-
) {
234+
/// Organizes document links by module prefix for navigation.
235+
fn populate_decls(doc: &Document, module_map: &mut ModuleMap) {
215236
let module_prefixes = &doc.module_info.module_prefixes;
216237
if let Some(doc_links) = module_map.get_mut(module_prefixes) {
217238
populate_doc_links(doc, doc_links)
218239
} else {
219-
let mut doc_links: BTreeMap<BlockTitle, Vec<DocLink>> = BTreeMap::new();
240+
let mut doc_links = DocLinkMap::new();
220241
populate_doc_links(doc, &mut doc_links);
221242
module_map.insert(module_prefixes.clone(), doc_links);
222243
}
223244
}
224-
fn populate_modules(
225-
doc: &Document,
226-
module_map: &mut BTreeMap<ModulePrefixes, BTreeMap<BlockTitle, Vec<DocLink>>>,
227-
) {
245+
/// Creates links to parent modules for hierarchical navigation.
246+
fn populate_modules(doc: &Document, module_map: &mut ModuleMap) {
228247
let mut module_clone = doc.module_info.clone();
229248
while module_clone.parent().is_some() {
230249
let html_filename = if module_clone.depth() > 2 {
@@ -257,16 +276,13 @@ fn populate_modules(
257276
}
258277
}
259278
} else {
260-
let mut doc_links: BTreeMap<BlockTitle, Vec<DocLink>> = BTreeMap::new();
279+
let mut doc_links = DocLinkMap::new();
261280
doc_links.insert(BlockTitle::Modules, vec![module_link]);
262281
module_map.insert(module_prefixes.clone(), doc_links);
263282
}
264283
module_clone.module_prefixes.pop();
265284
}
266285
}
267-
fn populate_all_doc(doc: &Document, all_docs: &mut DocLinks) {
268-
populate_doc_links(doc, &mut all_docs.links);
269-
}
270286

271287
/// The finalized HTML file contents.
272288
#[derive(Debug)]

0 commit comments

Comments
 (0)