Coverage Report

Created: 2025-10-12 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wasm-smith/src/lib.rs
Line
Count
Source
1
//! A WebAssembly test case generator.
2
//!
3
//! ## Usage
4
//!
5
//! First, use [`cargo fuzz`](https://github.com/rust-fuzz/cargo-fuzz) to define
6
//! a new fuzz target:
7
//!
8
//! ```shell
9
//! $ cargo fuzz add my_wasm_smith_fuzz_target
10
//! ```
11
//!
12
//! Next, add `wasm-smith` to your dependencies:
13
//!
14
//! ```shell
15
//! $ cargo add wasm-smith
16
//! ```
17
//!
18
//! Then, define your fuzz target so that it takes arbitrary
19
//! `wasm_smith::Module`s as an argument, convert the module into serialized
20
//! Wasm bytes via the `to_bytes` method, and then feed it into your system:
21
//!
22
//! ```no_run
23
//! // fuzz/fuzz_targets/my_wasm_smith_fuzz_target.rs
24
//!
25
//! #![no_main]
26
//!
27
//! # #[cfg(not(target_family = "wasm"))] mod x {
28
//! use libfuzzer_sys::fuzz_target;
29
//! use wasm_smith::Module;
30
//!
31
//! fuzz_target!(|module: Module| {
32
//!     let wasm_bytes = module.to_bytes();
33
//!
34
//!     // Your code here...
35
//! });
36
//! # }
37
//! ```
38
//!
39
//! Finally, start fuzzing:
40
//!
41
//! ```shell
42
//! $ cargo fuzz run my_wasm_smith_fuzz_target
43
//! ```
44
//!
45
//! > **Note:** For a real world example, also check out [the `validate` fuzz
46
//! > target](https://github.com/bytecodealliance/wasm-tools/blob/main/fuzz/src/validate.rs)
47
//! > defined in this repository. Using the `wasmparser` crate, it checks that
48
//! > every module generated by `wasm-smith` validates successfully.
49
//!
50
//! ## Design
51
//!
52
//! The design and implementation strategy of wasm-smith is outlined in
53
//! [this article](https://fitzgeraldnick.com/2020/08/24/writing-a-test-case-generator.html).
54
55
#![cfg_attr(docsrs, feature(doc_cfg))]
56
#![deny(missing_docs, missing_debug_implementations)]
57
// Needed for the `instructions!` macro in `src/code_builder.rs`.
58
#![recursion_limit = "512"]
59
60
#[cfg(feature = "component-model")]
61
mod component;
62
mod config;
63
mod core;
64
65
pub use crate::core::{InstructionKind, InstructionKinds, Module};
66
use arbitrary::{Result, Unstructured};
67
#[cfg(feature = "component-model")]
68
pub use component::Component;
69
pub use config::{Config, MemoryOffsetChoices};
70
use std::{collections::HashSet, fmt::Write, str};
71
use wasm_encoder::MemoryType;
72
73
#[doc(hidden)]
74
pub use config::InternalOptionalConfig;
75
76
944k
pub(crate) fn page_size(mem: &MemoryType) -> u32 {
77
    const DEFAULT_WASM_PAGE_SIZE_LOG2: u32 = 16;
78
944k
    1 << mem.page_size_log2.unwrap_or(DEFAULT_WASM_PAGE_SIZE_LOG2)
79
944k
}
80
81
/// Do something an arbitrary number of times.
82
///
83
/// The callback can return `false` to exit the loop early.
84
833k
pub(crate) fn arbitrary_loop<'a>(
85
833k
    u: &mut Unstructured<'a>,
86
833k
    min: usize,
87
833k
    max: usize,
88
833k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
833k
) -> Result<()> {
90
833k
    assert!(max >= min);
91
833k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
833k
    for _ in 0..(max - min) {
97
6.57M
        let keep_going = u.arbitrary().unwrap_or(false);
98
6.57M
        if !keep_going {
99
652k
            break;
100
5.92M
        }
101
102
5.92M
        if !f(u)? {
103
2.50k
            break;
104
5.92M
        }
105
    }
106
107
833k
    Ok(())
108
833k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_elems::{closure#5}::{closure#2}>
Line
Count
Source
84
25.5k
pub(crate) fn arbitrary_loop<'a>(
85
25.5k
    u: &mut Unstructured<'a>,
86
25.5k
    min: usize,
87
25.5k
    max: usize,
88
25.5k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
25.5k
) -> Result<()> {
90
25.5k
    assert!(max >= min);
91
25.5k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
25.5k
    for _ in 0..(max - min) {
97
401k
        let keep_going = u.arbitrary().unwrap_or(false);
98
401k
        if !keep_going {
99
12.9k
            break;
100
388k
        }
101
102
388k
        if !f(u)? {
103
0
            break;
104
388k
        }
105
    }
106
107
25.5k
    Ok(())
108
25.5k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_elems::{closure#5}::{closure#3}>
Line
Count
Source
84
21.6k
pub(crate) fn arbitrary_loop<'a>(
85
21.6k
    u: &mut Unstructured<'a>,
86
21.6k
    min: usize,
87
21.6k
    max: usize,
88
21.6k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
21.6k
) -> Result<()> {
90
21.6k
    assert!(max >= min);
91
21.6k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
21.6k
    for _ in 0..(max - min) {
97
643k
        let keep_going = u.arbitrary().unwrap_or(false);
98
643k
        if !keep_going {
99
11.3k
            break;
100
632k
        }
101
102
632k
        if !f(u)? {
103
0
            break;
104
632k
        }
105
    }
106
107
21.6k
    Ok(())
108
21.6k
}
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_instance_type::{closure#0}::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_component_type::{closure#0}::{closure#0}>
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_data::{closure#4}>
Line
Count
Source
84
16.0k
pub(crate) fn arbitrary_loop<'a>(
85
16.0k
    u: &mut Unstructured<'a>,
86
16.0k
    min: usize,
87
16.0k
    max: usize,
88
16.0k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
16.0k
) -> Result<()> {
90
16.0k
    assert!(max >= min);
91
16.0k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
16.0k
    for _ in 0..(max - min) {
97
48.3k
        let keep_going = u.arbitrary().unwrap_or(false);
98
48.3k
        if !keep_going {
99
15.2k
            break;
100
33.0k
        }
101
102
33.0k
        if !f(u)? {
103
0
            break;
104
33.0k
        }
105
    }
106
107
16.0k
    Ok(())
108
16.0k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_tags::{closure#0}>
Line
Count
Source
84
4.14k
pub(crate) fn arbitrary_loop<'a>(
85
4.14k
    u: &mut Unstructured<'a>,
86
4.14k
    min: usize,
87
4.14k
    max: usize,
88
4.14k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
4.14k
) -> Result<()> {
90
4.14k
    assert!(max >= min);
91
4.14k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
4.14k
    for _ in 0..(max - min) {
97
64.9k
        let keep_going = u.arbitrary().unwrap_or(false);
98
64.9k
        if !keep_going {
99
3.71k
            break;
100
61.2k
        }
101
102
61.2k
        if !f(u)? {
103
109
            break;
104
61.0k
        }
105
    }
106
107
4.14k
    Ok(())
108
4.14k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_elems::{closure#5}>
Line
Count
Source
84
14.7k
pub(crate) fn arbitrary_loop<'a>(
85
14.7k
    u: &mut Unstructured<'a>,
86
14.7k
    min: usize,
87
14.7k
    max: usize,
88
14.7k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
14.7k
) -> Result<()> {
90
14.7k
    assert!(max >= min);
91
14.7k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
14.7k
    for _ in 0..(max - min) {
97
65.5k
        let keep_going = u.arbitrary().unwrap_or(false);
98
65.5k
        if !keep_going {
99
13.7k
            break;
100
51.7k
        }
101
102
51.7k
        if !f(u)? {
103
0
            break;
104
51.7k
        }
105
    }
106
107
14.7k
    Ok(())
108
14.7k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_funcs::{closure#1}>
Line
Count
Source
84
17.6k
pub(crate) fn arbitrary_loop<'a>(
85
17.6k
    u: &mut Unstructured<'a>,
86
17.6k
    min: usize,
87
17.6k
    max: usize,
88
17.6k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
17.6k
) -> Result<()> {
90
17.6k
    assert!(max >= min);
91
17.6k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
17.6k
    for _ in 0..(max - min) {
97
362k
        let keep_going = u.arbitrary().unwrap_or(false);
98
362k
        if !keep_going {
99
17.0k
            break;
100
345k
        }
101
102
345k
        if !f(u)? {
103
190
            break;
104
344k
        }
105
    }
106
107
17.6k
    Ok(())
108
17.6k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_locals::{closure#0}>
Line
Count
Source
84
344k
pub(crate) fn arbitrary_loop<'a>(
85
344k
    u: &mut Unstructured<'a>,
86
344k
    min: usize,
87
344k
    max: usize,
88
344k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
344k
) -> Result<()> {
90
344k
    assert!(max >= min);
91
344k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
344k
    for _ in 0..(max - min) {
97
2.34M
        let keep_going = u.arbitrary().unwrap_or(false);
98
2.34M
        if !keep_going {
99
330k
            break;
100
2.01M
        }
101
102
2.01M
        if !f(u)? {
103
0
            break;
104
2.01M
        }
105
    }
106
107
344k
    Ok(())
108
344k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_tables::{closure#0}>
Line
Count
Source
84
20.8k
pub(crate) fn arbitrary_loop<'a>(
85
20.8k
    u: &mut Unstructured<'a>,
86
20.8k
    min: usize,
87
20.8k
    max: usize,
88
20.8k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
20.8k
) -> Result<()> {
90
20.8k
    assert!(max >= min);
91
20.8k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
20.8k
    for _ in 0..(max - min) {
97
46.0k
        let keep_going = u.arbitrary().unwrap_or(false);
98
46.0k
        if !keep_going {
99
13.4k
            break;
100
32.5k
        }
101
102
32.5k
        if !f(u)? {
103
1.11k
            break;
104
31.4k
        }
105
    }
106
107
20.8k
    Ok(())
108
20.8k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_exports::{closure#4}>
Line
Count
Source
84
20.8k
pub(crate) fn arbitrary_loop<'a>(
85
20.8k
    u: &mut Unstructured<'a>,
86
20.8k
    min: usize,
87
20.8k
    max: usize,
88
20.8k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
20.8k
) -> Result<()> {
90
20.8k
    assert!(max >= min);
91
20.8k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
20.8k
    for _ in 0..(max - min) {
97
91.4k
        let keep_going = u.arbitrary().unwrap_or(false);
98
91.4k
        if !keep_going {
99
19.3k
            break;
100
72.1k
        }
101
102
72.1k
        if !f(u)? {
103
297
            break;
104
71.8k
        }
105
    }
106
107
20.8k
    Ok(())
108
20.8k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_globals::{closure#0}>
Line
Count
Source
84
20.8k
pub(crate) fn arbitrary_loop<'a>(
85
20.8k
    u: &mut Unstructured<'a>,
86
20.8k
    min: usize,
87
20.8k
    max: usize,
88
20.8k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
20.8k
) -> Result<()> {
90
20.8k
    assert!(max >= min);
91
20.8k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
20.8k
    for _ in 0..(max - min) {
97
142k
        let keep_going = u.arbitrary().unwrap_or(false);
98
142k
        if !keep_going {
99
19.6k
            break;
100
122k
        }
101
102
122k
        if !f(u)? {
103
92
            break;
104
122k
        }
105
    }
106
107
20.8k
    Ok(())
108
20.8k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_imports::{closure#0}>
Line
Count
Source
84
20.8k
pub(crate) fn arbitrary_loop<'a>(
85
20.8k
    u: &mut Unstructured<'a>,
86
20.8k
    min: usize,
87
20.8k
    max: usize,
88
20.8k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
20.8k
) -> Result<()> {
90
20.8k
    assert!(max >= min);
91
20.8k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
20.8k
    for _ in 0..(max - min) {
97
177k
        let keep_going = u.arbitrary().unwrap_or(false);
98
177k
        if !keep_going {
99
18.4k
            break;
100
158k
        }
101
102
158k
        if !f(u)? {
103
311
            break;
104
158k
        }
105
    }
106
107
20.8k
    Ok(())
108
20.8k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_memories::{closure#0}>
Line
Count
Source
84
20.8k
pub(crate) fn arbitrary_loop<'a>(
85
20.8k
    u: &mut Unstructured<'a>,
86
20.8k
    min: usize,
87
20.8k
    max: usize,
88
20.8k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
20.8k
) -> Result<()> {
90
20.8k
    assert!(max >= min);
91
20.8k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
20.8k
    for _ in 0..(max - min) {
97
66.3k
        let keep_going = u.arbitrary().unwrap_or(false);
98
66.3k
        if !keep_going {
99
18.1k
            break;
100
48.2k
        }
101
102
48.2k
        if !f(u)? {
103
399
            break;
104
47.8k
        }
105
    }
106
107
20.8k
    Ok(())
108
20.8k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_func_type::{closure#0}>
Line
Count
Source
84
142k
pub(crate) fn arbitrary_loop<'a>(
85
142k
    u: &mut Unstructured<'a>,
86
142k
    min: usize,
87
142k
    max: usize,
88
142k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
142k
) -> Result<()> {
90
142k
    assert!(max >= min);
91
142k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
142k
    for _ in 0..(max - min) {
97
1.33M
        let keep_going = u.arbitrary().unwrap_or(false);
98
1.33M
        if !keep_going {
99
91.2k
            break;
100
1.24M
        }
101
102
1.24M
        if !f(u)? {
103
0
            break;
104
1.24M
        }
105
    }
106
107
142k
    Ok(())
108
142k
}
wasm_smith::arbitrary_loop::<<wasm_smith::core::Module>::arbitrary_func_type::{closure#1}>
Line
Count
Source
84
142k
pub(crate) fn arbitrary_loop<'a>(
85
142k
    u: &mut Unstructured<'a>,
86
142k
    min: usize,
87
142k
    max: usize,
88
142k
    mut f: impl FnMut(&mut Unstructured<'a>) -> Result<bool>,
89
142k
) -> Result<()> {
90
142k
    assert!(max >= min);
91
142k
    for _ in 0..min {
92
0
        if !f(u)? {
93
0
            return Err(arbitrary::Error::IncorrectFormat);
94
0
        }
95
    }
96
142k
    for _ in 0..(max - min) {
97
788k
        let keep_going = u.arbitrary().unwrap_or(false);
98
788k
        if !keep_going {
99
67.1k
            break;
100
721k
        }
101
102
721k
        if !f(u)? {
103
0
            break;
104
721k
        }
105
    }
106
107
142k
    Ok(())
108
142k
}
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_enum_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_func_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_func_type::{closure#1}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_flags_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_tuple_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_module_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_record_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_type_section::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_variant_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_import_section::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_canonical_section::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<<wasm_smith::component::ComponentBuilder>::arbitrary_core_type_section::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<wasm_smith::component::arbitrary_func_type::{closure#0}>
Unexecuted instantiation: wasm_smith::arbitrary_loop::<wasm_smith::component::arbitrary_func_type::{closure#1}>
109
110
// Mirror what happens in `Arbitrary for String`, but do so with a clamped size.
111
397k
pub(crate) fn limited_str<'a>(max_size: usize, u: &mut Unstructured<'a>) -> Result<&'a str> {
112
397k
    let size = u.arbitrary_len::<u8>()?;
113
397k
    let size = std::cmp::min(size, max_size);
114
397k
    match str::from_utf8(u.peek_bytes(size).unwrap()) {
115
24.0k
        Ok(s) => {
116
24.0k
            u.bytes(size).unwrap();
117
24.0k
            Ok(s)
118
        }
119
373k
        Err(e) => {
120
373k
            let i = e.valid_up_to();
121
373k
            let valid = u.bytes(i).unwrap();
122
373k
            let s = str::from_utf8(valid).unwrap();
123
373k
            Ok(s)
124
        }
125
    }
126
397k
}
127
128
397k
pub(crate) fn limited_string(max_size: usize, u: &mut Unstructured) -> Result<String> {
129
397k
    Ok(limited_str(max_size, u)?.into())
130
397k
}
131
132
80.6k
pub(crate) fn unique_string(
133
80.6k
    max_size: usize,
134
80.6k
    names: &mut HashSet<String>,
135
80.6k
    u: &mut Unstructured,
136
80.6k
) -> Result<String> {
137
80.6k
    let mut name = limited_string(max_size, u)?;
138
140k
    while names.contains(&name) {
139
59.6k
        write!(&mut name, "{}", names.len()).unwrap();
140
59.6k
    }
141
80.6k
    names.insert(name.clone());
142
80.6k
    Ok(name)
143
80.6k
}
144
145
#[cfg(feature = "component-model")]
146
0
pub(crate) fn unique_kebab_string(
147
0
    max_size: usize,
148
0
    names: &mut HashSet<String>,
149
0
    u: &mut Unstructured,
150
0
) -> Result<String> {
151
0
    let size = std::cmp::min(u.arbitrary_len::<u8>()?, max_size);
152
0
    let mut name = String::with_capacity(size);
153
0
    let mut require_alpha = true;
154
0
    for _ in 0..size {
155
0
        name.push(match u.int_in_range::<u8>(0..=36)? {
156
0
            x if (0..26).contains(&x) => {
157
0
                require_alpha = false;
158
0
                (b'a' + x) as char
159
            }
160
0
            x if (26..36).contains(&x) => {
161
0
                if require_alpha {
162
0
                    require_alpha = false;
163
0
                    (b'a' + (x - 26)) as char
164
                } else {
165
0
                    (b'0' + (x - 26)) as char
166
                }
167
            }
168
0
            x if x == 36 => {
169
0
                if require_alpha {
170
0
                    require_alpha = false;
171
0
                    'a'
172
                } else {
173
0
                    require_alpha = true;
174
0
                    '-'
175
                }
176
            }
177
0
            _ => unreachable!(),
178
        });
179
    }
180
181
0
    if name.is_empty() || name.ends_with('-') {
182
0
        name.push('a');
183
0
    }
184
185
0
    while names.contains(&name) {
186
0
        write!(&mut name, "{}", names.len()).unwrap();
187
0
    }
188
189
0
    names.insert(name.clone());
190
191
0
    Ok(name)
192
0
}
193
194
#[cfg(feature = "component-model")]
195
0
pub(crate) fn unique_url(
196
0
    max_size: usize,
197
0
    names: &mut HashSet<String>,
198
0
    u: &mut Unstructured,
199
0
) -> Result<String> {
200
0
    let path = unique_kebab_string(max_size, names, u)?;
201
0
    Ok(format!("https://example.com/{path}"))
202
0
}