summaryrefslogtreecommitdiffstats
path: root/dom/base/fragmentdirectives/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/fragmentdirectives/lib.rs')
-rw-r--r--dom/base/fragmentdirectives/lib.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/dom/base/fragmentdirectives/lib.rs b/dom/base/fragmentdirectives/lib.rs
new file mode 100644
index 0000000000..0003849eb7
--- /dev/null
+++ b/dom/base/fragmentdirectives/lib.rs
@@ -0,0 +1,158 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use nsstring::{nsCString, nsString};
+use thin_vec::ThinVec;
+pub mod fragment_directive_impl;
+mod test;
+
+/// This struct contains the percent-decoded parts of a text directive.
+/// All parts besides `start` are optional (which is indicated by an empty string).
+///
+/// This struct uses Gecko String types, whereas the parser internally uses Rust types.
+/// Therefore, conversion functions are provided.
+#[repr(C)]
+pub struct TextDirective {
+ prefix: nsString,
+ start: nsString,
+ end: nsString,
+ suffix: nsString,
+}
+
+impl TextDirective {
+ /// Creates a `FragmentDirectiveElement` object from a `FragmentDirectiveElementInternal` object
+ /// (which uses Rust string types).
+ fn from_rust_type(element: &fragment_directive_impl::TextDirective) -> Self {
+ Self {
+ prefix: element
+ .prefix()
+ .as_ref()
+ .map_or_else(nsString::new, |token| nsString::from(token.value())),
+ start: element
+ .start()
+ .as_ref()
+ .map_or_else(nsString::new, |token| nsString::from(token.value())),
+ end: element
+ .end()
+ .as_ref()
+ .map_or_else(nsString::new, |token| nsString::from(token.value())),
+ suffix: element
+ .suffix()
+ .as_ref()
+ .map_or_else(nsString::new, |token| nsString::from(token.value())),
+ }
+ }
+
+ /// Converts the contents of this object into Rust types.
+ /// Returns `None` if the given fragment is not valid.
+ /// The only invalid condition is a fragment that is missing the `start` token.
+ fn to_rust_type(&self) -> Option<fragment_directive_impl::TextDirective> {
+ fragment_directive_impl::TextDirective::from_parts(
+ self.prefix.to_string(),
+ self.start.to_string(),
+ self.end.to_string(),
+ self.suffix.to_string(),
+ )
+ }
+}
+
+/// Result of the `parse_fragment_directive()` function.
+///
+/// The result contains the original given URL without the fragment directive,
+/// a unsanitized string version of the extracted fragment directive,
+/// and an array of the parsed text directives.
+#[repr(C)]
+pub struct ParsedFragmentDirectiveResult {
+ url_without_fragment_directive: nsCString,
+ fragment_directive: nsCString,
+ text_directives: ThinVec<TextDirective>,
+}
+
+/// Parses the fragment directive from a given URL.
+///
+/// This function writes the result data into `result`.
+/// The result consists of
+/// - the input url without the fragment directive,
+/// - the fragment directive as unparsed string,
+/// - a list of the parsed and percent-decoded text directives.
+///
+/// Directives which are unknown will be ignored.
+/// If new directive types are added in the future, they should also be considered here.
+/// This function returns false if no fragment directive is found, or it could not be parsed.
+#[no_mangle]
+pub extern "C" fn parse_fragment_directive(
+ url: &nsCString,
+ result: &mut ParsedFragmentDirectiveResult,
+) -> bool {
+ // sanitize inputs
+ result.url_without_fragment_directive = nsCString::new();
+ result.fragment_directive = nsCString::new();
+ result.text_directives.clear();
+
+ let url_as_rust_string = url.to_utf8();
+ if let Some((stripped_url, fragment_directive, text_directives)) =
+ fragment_directive_impl::parse_fragment_directive_and_remove_it_from_hash(
+ &url_as_rust_string,
+ )
+ {
+ result
+ .url_without_fragment_directive
+ .assign(&stripped_url);
+ result.fragment_directive.assign(&fragment_directive);
+ result.text_directives.extend(
+ text_directives
+ .iter()
+ .map(|text_directive| TextDirective::from_rust_type(text_directive)),
+ );
+ return true;
+ }
+ false
+}
+
+/// Creates a percent-encoded fragment directive string from a given list of `FragmentDirectiveElement`s.
+///
+/// The returned string has this form:
+/// `:~:text=[prefix1-,]start1[,end1][,-suffix1]&text=[prefix2-,]start2[,end2][,-suffix2]`
+///
+/// Invalid `FragmentDirectiveElement`s are ignored, where "invalid" means that no `start` token is provided.
+/// If there are no valid `FragmentDirectiveElement`s, an empty string is returned.
+#[no_mangle]
+pub extern "C" fn create_fragment_directive(
+ text_directives: &ThinVec<TextDirective>,
+ fragment_directive: &mut nsCString,
+) -> bool {
+ let directives_rust = Vec::from_iter(
+ text_directives
+ .iter()
+ .filter_map(|fragment| fragment.to_rust_type()),
+ );
+ if let Some(fragment_directive_rust) =
+ fragment_directive_impl::create_fragment_directive_string(&directives_rust)
+ {
+ fragment_directive.assign(&fragment_directive_rust);
+ return true;
+ }
+
+ false
+}
+
+/// Creates a percent-encoded text directive string for a single text directive.
+/// The returned string has the form `text=[prefix-,]start[,end][,-suffix]`.
+/// If the provided `TextDirective` is invalid (i.e. it has no `start` attribute),
+/// the outparam `directive_string` is empty and the function returns false.
+#[no_mangle]
+pub extern "C" fn create_text_directive(
+ text_directive: &TextDirective,
+ directive_string: &mut nsCString,
+) -> bool {
+ if let Some(text_directive_rust) = text_directive.to_rust_type() {
+ if let Some(text_directive_string_rust) =
+ fragment_directive_impl::create_text_directive_string(&text_directive_rust)
+ {
+ directive_string.assign(&text_directive_string_rust);
+ return true;
+ }
+ }
+ false
+}