// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License.
use std::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
ops, str,
};
usecrate::error::{ErrorKind, Result};
/// A GUID for an item in a bookmark tree. #[derive(Clone)] pubstruct Guid(Repr);
/// Indicates if the GUID is valid. Implemented for byte slices and GUIDs. pubtrait IsValidGuid { fn is_valid_guid(&self) -> bool;
}
/// The internal representation of a GUID. Valid GUIDs are 12 bytes, and contain /// only Base64url characters; we can store them on the stack without a heap /// allocation. However, both local and remote items might have invalid GUIDs, /// in which case we fall back to a heap-allocated string. #[derive(Clone)] enum Repr {
Valid([u8; 12]),
Invalid(Box<str>),
}
/// The Places root GUID, used to root all items in a bookmark tree. pubconst ROOT_GUID: Guid = Guid(Repr::Valid(*b"root________"));
/// The bookmarks toolbar GUID. pubconst TOOLBAR_GUID: Guid = Guid(Repr::Valid(*b"toolbar_____"));
/// The bookmarks menu GUID. pubconst MENU_GUID: Guid = Guid(Repr::Valid(*b"menu________"));
/// The "Other Bookmarks" GUID, used to hold items without a parent. pubconst UNFILED_GUID: Guid = Guid(Repr::Valid(*b"unfiled_____"));
/// The mobile bookmarks GUID. pubconst MOBILE_GUID: Guid = Guid(Repr::Valid(*b"mobile______"));
/// The tags root GUID. pubconst TAGS_GUID: Guid = Guid(Repr::Valid(*b"tags________"));
impl Guid { /// Converts a UTF-8 byte slice to a GUID. pubfn from_utf8(b: &[u8]) -> Result<Guid> { let repr = if b.is_valid_guid() { letmut bytes = [0u8; 12];
bytes.copy_from_slice(b);
Repr::Valid(bytes)
} else { match str::from_utf8(b) {
Ok(s) => Repr::Invalid(s.into()),
Err(err) => return Err(err.into()),
}
};
Ok(Guid(repr))
}
/// Converts a UTF-16 byte slice to a GUID. pubfn from_utf16(b: &[u16]) -> Result<Guid> { let repr = if b.is_valid_guid() { letmut bytes = [0u8; 12]; for (index, &byte) in b.iter().enumerate() { if byte > u16::from(u8::max_value()) { return Err(ErrorKind::InvalidByte(byte).into());
}
bytes[index] = byte as u8;
}
Repr::Valid(bytes)
} else { match String::from_utf16(b) {
Ok(s) => Repr::Invalid(s.into()),
Err(err) => return Err(err.into()),
}
};
Ok(Guid(repr))
}
/// Returns the GUID as a byte slice. #[inline] pubfn as_bytes(&self) -> &[u8] { matchself.0 {
Repr::Valid(ref bytes) => bytes,
Repr::Invalid(ref s) => s.as_bytes(),
}
}
/// Returns the GUID as a string slice. #[inline] pubfn as_str(&self) -> &str { // We actually could use from_utf8_unchecked here, and depending on how // often we end up doing this, it's arguable that we should. We know // already this is valid utf8, since we know that we only ever create // these while respecting is_valid (and moreover, we assert that // `s.is_char_boundary(12)` in `Guid::from`). matchself.0 {
Repr::Valid(ref bytes) => str::from_utf8(bytes).unwrap(),
Repr::Invalid(ref s) => s,
}
}
/// Indicates if the GUID is one of the five Places built-in roots, /// including the user content roots and the tags root. #[inline] pubfn is_built_in_root(&self) -> bool { self == TOOLBAR_GUID
|| self == MENU_GUID
|| self == UNFILED_GUID
|| self == MOBILE_GUID
|| self == TAGS_GUID
}
}
#[test] fn is_valid() { let valid_guids = &[ "bookmarkAAAA", "menu________", "__folderBB__", "queryAAAAAAA",
]; for s in valid_guids {
assert!(s.as_bytes().is_valid_guid(), "{:?} should validate", s);
assert!(Guid::from(*s).is_valid_guid());
}
let invalid_guids = &["bookmarkAAA", "folder!", "b@dgu1d!"]; for s in invalid_guids {
assert!(!s.as_bytes().is_valid_guid(), "{:?} should not validate", s);
assert!(!Guid::from(*s).is_valid_guid());
}
let invalid_guid_bytes: &[[u8; 12]] =
&[[113, 117, 101, 114, 121, 65, 225, 193, 65, 65, 65, 65]]; for bytes in invalid_guid_bytes {
assert!(!bytes.is_valid_guid(), "{:?} should not validate", bytes);
Guid::from_utf8(bytes).expect_err("Should not make GUID from invalid UTF-8");
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.