aboutsummaryrefslogtreecommitdiff
path: root/nearby/presence/np_adv/src/extended/serialize/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'nearby/presence/np_adv/src/extended/serialize/mod.rs')
-rw-r--r--nearby/presence/np_adv/src/extended/serialize/mod.rs133
1 files changed, 101 insertions, 32 deletions
diff --git a/nearby/presence/np_adv/src/extended/serialize/mod.rs b/nearby/presence/np_adv/src/extended/serialize/mod.rs
index e753281..9d82273 100644
--- a/nearby/presence/np_adv/src/extended/serialize/mod.rs
+++ b/nearby/presence/np_adv/src/extended/serialize/mod.rs
@@ -161,6 +161,12 @@ pub struct AdvBuilder {
advertisement_type: AdvertisementType,
}
+impl AsMut<AdvBuilder> for AdvBuilder {
+ fn as_mut(&mut self) -> &mut AdvBuilder {
+ self
+ }
+}
+
impl AdvBuilder {
/// Build an [AdvBuilder].
pub fn new(advertisement_type: AdvertisementType) -> Self {
@@ -170,17 +176,10 @@ impl AdvBuilder {
Self { adv, section_count: 0, advertisement_type }
}
- /// Create a section builder.
- ///
- /// The builder will not accept more DEs than can fit given the space already used in the
- /// advertisement by previous sections, if any.
- ///
- /// Once the builder is populated, add it to the originating advertisement with
- /// [SectionBuilder.add_to_advertisement].
- pub fn section_builder<SE: SectionEncoder>(
- &mut self,
- section_encoder: SE,
- ) -> Result<SectionBuilder<SE>, AddSectionError> {
+ fn prepare_section_builder_buffer_and_de_offset<SE: SectionEncoder>(
+ &self,
+ ) -> Result<(CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>, DataElementOffset), AddSectionError>
+ {
// section header and identity prefix
let prefix_len = 1 + SE::PREFIX_LEN;
let minimum_section_len = prefix_len + SE::SUFFIX_LEN;
@@ -203,16 +202,49 @@ impl AdvBuilder {
// placeholder for section header and identity prefix
section.resize(prefix_len, 0);
- Ok(SectionBuilder {
- section: CapacityLimitedVec {
- vec: section,
- // won't underflow: checked above
- capacity: available_len - SE::SUFFIX_LEN,
- },
- section_encoder,
- adv_builder: self,
- next_de_offset: SE::INITIAL_DE_OFFSET,
- })
+ let section = CapacityLimitedVec {
+ vec: section,
+ // won't underflow: checked above
+ capacity: available_len - SE::SUFFIX_LEN,
+ };
+ let next_de_offset = SE::INITIAL_DE_OFFSET;
+ Ok((section, next_de_offset))
+ }
+
+ /// Create a section builder whose contents may be added to this advertisement.
+ ///
+ /// The builder will not accept more DEs than can fit given the space already used in the
+ /// advertisement by previous sections, if any.
+ ///
+ /// Once the builder is populated, add it to the originating advertisement with
+ /// [SectionBuilder.add_to_advertisement].
+ pub fn section_builder<SE: SectionEncoder>(
+ &mut self,
+ section_encoder: SE,
+ ) -> Result<SectionBuilder<&mut AdvBuilder, SE>, AddSectionError> {
+ let (section, next_de_offset) =
+ self.prepare_section_builder_buffer_and_de_offset::<SE>()?;
+
+ Ok(SectionBuilder { section, section_encoder, adv_builder: self, next_de_offset })
+ }
+
+ /// Create a section builder which actually takes ownership of this advertisement builder.
+ ///
+ /// This is unlike `AdvertisementBuilder#section_builder` in that the returned section
+ /// builder will take ownership of this advertisement builder, if the operation was
+ /// successful. Otherwise, this advertisement builder will be returned back to the
+ /// caller unaltered as part of the `Err` arm.
+ #[allow(clippy::result_large_err)]
+ pub fn into_section_builder<SE: SectionEncoder>(
+ self,
+ section_encoder: SE,
+ ) -> Result<SectionBuilder<AdvBuilder, SE>, (AdvBuilder, AddSectionError)> {
+ match self.prepare_section_builder_buffer_and_de_offset::<SE>() {
+ Ok((section, next_de_offset)) => {
+ Ok(SectionBuilder { section, section_encoder, adv_builder: self, next_de_offset })
+ }
+ Err(err) => Err((self, err)),
+ }
}
/// Convert the builder into an encoded advertisement.
@@ -220,6 +252,12 @@ impl AdvBuilder {
EncodedAdvertisement { adv: to_array_view(self.adv) }
}
+ /// Gets the current number of sections added to this advertisement
+ /// builder, not counting any outstanding SectionBuilders.
+ pub fn section_count(&self) -> usize {
+ self.section_count
+ }
+
/// Add the section, which must have come from a SectionBuilder generated from this, into this
/// advertisement.
fn add_section(&mut self, section: EncodedSection) {
@@ -279,24 +317,56 @@ type EncodedSection = ArrayView<u8, NP_ADV_MAX_SECTION_LEN>;
/// Accumulates data elements and encodes them into a section.
#[derive(Debug)]
-pub struct SectionBuilder<'a, SE: SectionEncoder> {
+pub struct SectionBuilder<R: AsMut<AdvBuilder>, SE: SectionEncoder> {
/// Contains the section header, the identity-specified overhead, and any DEs added
pub(crate) section: CapacityLimitedVec<u8, NP_ADV_MAX_SECTION_LEN>,
section_encoder: SE,
- /// mut ref to enforce only one active section builder at a time
- adv_builder: &'a mut AdvBuilder,
+ /// mut ref-able to enforce only one active section builder at a time
+ adv_builder: R,
next_de_offset: DataElementOffset,
}
-impl<'a, SE: SectionEncoder> SectionBuilder<'a, SE> {
+impl<'a, SE: SectionEncoder> SectionBuilder<&'a mut AdvBuilder, SE> {
/// Add this builder to the advertisement that created it.
pub fn add_to_advertisement(self) {
- let adv_builder = self.adv_builder;
+ let _ = self.add_to_advertisement_internal();
+ }
+}
+
+impl<SE: SectionEncoder> SectionBuilder<AdvBuilder, SE> {
+ /// Gets the 0-based index of the section currently under construction
+ /// in the context of the containing advertisement.
+ pub fn section_index(&self) -> usize {
+ self.adv_builder.section_count()
+ }
+ /// Add this builder to the advertisement that created it,
+ /// and returns the containing advertisement back to the caller.
+ pub fn add_to_advertisement(self) -> AdvBuilder {
+ self.add_to_advertisement_internal()
+ }
+}
+
+impl<R: AsMut<AdvBuilder>, SE: SectionEncoder> SectionBuilder<R, SE> {
+ /// Add this builder to the advertisement that created it.
+ /// Returns the mut-refable to the advertisement builder
+ /// which the contents of this section builder were added to.
+ fn add_to_advertisement_internal(mut self) -> R {
+ let adv_builder = self.adv_builder.as_mut();
+ let adv_builder_header_byte = adv_builder.header_byte();
adv_builder.add_section(Self::build_section(
+ adv_builder_header_byte,
self.section.into_inner(),
self.section_encoder,
- adv_builder,
- ))
+ ));
+ self.adv_builder
+ }
+
+ /// Gets the derived salt which will be employed for the next DE offset.
+ ///
+ /// Suitable for scenarios (like FFI) where a closure would be inappropriate
+ /// for DE construction, and interaction with the client is preferred.
+ pub fn next_de_salt(&self) -> SE::DerivedSalt {
+ self.section_encoder.de_salt(self.next_de_offset)
}
/// Add a data element to the section with a closure that returns a `Result`.
@@ -306,8 +376,7 @@ impl<'a, SE: SectionEncoder> SectionBuilder<'a, SE> {
&mut self,
build_de: F,
) -> Result<(), AddDataElementError<E>> {
- let writer = build_de(self.section_encoder.de_salt(self.next_de_offset))
- .map_err(AddDataElementError::BuildDeError)?;
+ let writer = build_de(self.next_de_salt()).map_err(AddDataElementError::BuildDeError)?;
let orig_len = self.section.len();
// since we own the writer, and it's immutable, no race risk writing header w/ len then
@@ -357,9 +426,9 @@ impl<'a, SE: SectionEncoder> SectionBuilder<'a, SE> {
///
/// Implemented without self to avoid partial-move issues.
fn build_section(
+ adv_builder_header_byte: u8,
mut section_contents: tinyvec::ArrayVec<[u8; NP_ADV_MAX_SECTION_LEN]>,
mut section_encoder: SE,
- adv_builder: &AdvBuilder,
) -> EncodedSection {
// there is space because the capacity for DEs was restricted to allow it
section_contents.resize(section_contents.len() + SE::SUFFIX_LEN, 0);
@@ -372,7 +441,7 @@ impl<'a, SE: SectionEncoder> SectionBuilder<'a, SE> {
.expect("section length is always <=255 and non-negative");
section_encoder.postprocess(
- adv_builder.header_byte(),
+ adv_builder_header_byte,
section_contents[0],
&mut section_contents[1..],
);