Skip to content

Commit

Permalink
Switch suggest component from UDL to proc-macros
Browse files Browse the repository at this point in the history
  • Loading branch information
gruberb committed Sep 19, 2024
1 parent 7625a2c commit 3f0066a
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 371 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/build-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,39 @@ jobs:
- name: Install Jazzy
run: gem install jazzy

- name: Install xcpretty
run: |
sudo gem install xcpretty
- name: Build Dependencies
env:
NSS_DIR: ${{ github.workspace }}/libs/desktop/darwin-aarch64/nss
NSS_STATIC: 1
run: |
# Install virtual environment and setuptools + six
python3 -m venv venv
source venv/bin/activate
python3 -m pip install --upgrade pip setuptools six
# Clone the gyp repository
git clone https://chromium.googlesource.com/external/gyp.git tools/gyp
# Navigate to gyp directory and install it
cd tools/gyp
python3 setup.py install
cd ../..
# Install the required dependencies on macOS (replace tcl with tcl-tk)
brew install ninja zlib tcl-tk python
# Ensure the environment for desktop is correctly set up
# NSS for desktop has to be setup to build megazord
./libs/verify-desktop-environment.sh
- name: Build Swift docs
env:
NSS_DIR: ${{ github.workspace }}/libs/desktop/darwin-aarch64/nss
NSS_STATIC: 1
run: |
cd ./automation/swift-components-docs
./build.sh
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ fml.py
# Build static website files
automation/swift-components-docs/.build
automation/swift-components-docs/docs
automation/swift-components-docs/Sources/SwiftComponents/*.swift
automation/swift-components-docs/Sources/SwiftComponents/include/*.h
automation/swift-components-docs/Sources
automation/kotlin-components-docs/.gradle
automation/kotlin-components-docs/build
automation/kotlin-components-docs/src
Expand Down

This file was deleted.

21 changes: 21 additions & 0 deletions automation/swift-components-docs/generate-modulemap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

# Define the module name and path to the include directory
MODULE_NAME="MozillaRustComponents"
INCLUDE_DIR="Sources/SwiftComponents/include"
MODULEMAP_FILE="$INCLUDE_DIR/module.modulemap"

# Start creating the module map
echo "module $MODULE_NAME {" > "$MODULEMAP_FILE"

# Find all .h files in the include directory and add them to the module map
for header in "$INCLUDE_DIR"/*.h; do
echo " header \"$(basename "$header")\"" >> "$MODULEMAP_FILE"
done

# Add export statement to the end of the module map
echo " export *" >> "$MODULEMAP_FILE"
echo "}" >> "$MODULEMAP_FILE"

# Confirm module.modulemap was created
echo "module.modulemap generated at: $MODULEMAP_FILE"
94 changes: 35 additions & 59 deletions automation/swift-components-docs/generate-swift-project.sh
Original file line number Diff line number Diff line change
@@ -1,78 +1,54 @@
#!/usr/bin/env bash
#
# This script builds the Rust crate in its directory and generates Swift bindings, headers, and a module map.
# This script builds the Rust crate in its directory and generates Swift bindings,
# headers, and a module map using UniFFI in library mode.

FRAMEWORK_NAME="SwiftComponents"
set -euo pipefail # Ensure script exits on errors or unset variables

FRAMEWORK_NAME="SwiftComponents"
THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
REPO_ROOT="$( dirname "$( dirname "$THIS_DIR" )" )"
WORKING_DIR=$THIS_DIR

MANIFEST_PATH="$WORKING_DIR/Cargo.toml"

if [[ ! -f "$MANIFEST_PATH" ]]; then
echo "Could not locate Cargo.toml in $MANIFEST_PATH"
exit 1
fi

CRATE_NAME=$(grep --max-count=1 '^name =' "$MANIFEST_PATH" | cut -d '"' -f 2)
if [[ -z "$CRATE_NAME" ]]; then
echo "Could not determine crate name from $MANIFEST_PATH"
exit 1
fi

# Helper to run the cargo build command in a controlled environment.
# It's important that we don't let environment variables from the user's default
# desktop build environment leak into the iOS build, otherwise it might e.g.
# link against the desktop build of NSS.

WORKING_DIR="$THIS_DIR"
CARGO="$HOME/.cargo/bin/cargo"
LIBS_DIR="$REPO_ROOT/libs"

cargo_build () {
LIBS_DIR="$REPO_ROOT/libs/ios/arm64"

env -i \
NSS_STATIC=1 \
NSS_DIR="$LIBS_DIR/nss" \
PATH="${PATH}"
}

set -euvx

cargo_build aarch64-apple-ios

# Create directories for Swift files, headers, and module map
INCLUDE_DIR="$WORKING_DIR/Sources/$FRAMEWORK_NAME/include"
SWIFT_DIR="$WORKING_DIR/Sources/$FRAMEWORK_NAME"

mkdir -p "$INCLUDE_DIR"

# Generate Swift bindings and headers using uniffi-bindgen
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/remote_settings/src/remote_settings.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/nimbus/src/nimbus.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/support/error/src/errorsupport.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/support/rust-log-forwarder/src/rust_log_forwarder.udl" -l swift -o "$SWIFT_DIR"
# Build the Rust crate using Cargo
echo "Building the Rust crate..."
$CARGO build -p megazord --release

# Define the path to the generated Rust library
LIBRARY_FILE="$REPO_ROOT/target/release/libmegazord.dylib"
if [[ ! -f "$LIBRARY_FILE" ]]; then
echo "Error: Rust library not found at $LIBRARY_FILE"
exit 1
fi

# Move header files to the include directory
mv "$SWIFT_DIR"/*.h "$INCLUDE_DIR"
# Generate Swift bindings, headers, and module map using uniffi-bindgen
echo "Generating Swift bindings with uniffi-bindgen..."
$CARGO uniffi-bindgen generate --library "$LIBRARY_FILE" --language swift --out-dir "$SWIFT_DIR"

# Repeat for the other components if not focus
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/crashtest/src/crashtest.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/fxa-client/src/fxa_client.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/logins/src/logins.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/autofill/src/autofill.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/push/src/push.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/tabs/src/tabs.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/places/src/places.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/suggest/src/suggest.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/sync_manager/src/syncmanager.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/sync15/src/sync15.udl" -l swift -o "$SWIFT_DIR"
$CARGO uniffi-bindgen generate "$REPO_ROOT/components/as-ohttp-client/src/as_ohttp_client.udl" -l swift -o "$SWIFT_DIR"
# Move generated header files to the include directory
echo "Moving header files to include directory..."
mv "$SWIFT_DIR"/*.h "$INCLUDE_DIR" || {
echo "Error: Failed to move header files."
exit 1
}

# Move the header files to the include directory
mv "$SWIFT_DIR"/*.h "$INCLUDE_DIR"
# Remove any old modulemaps
echo "Cleaning up old module maps..."
rm -f "$SWIFT_DIR"/*.modulemap

rm -rf "$WORKING_DIR"/Sources/"$FRAMEWORK_NAME"/*.modulemap
# Generate a new module map
echo "Generating module map..."
if [[ ! -f "$WORKING_DIR/generate-modulemap.sh" ]]; then
echo "Error: generate-modulemap.sh script not found."
exit 1
fi
"$WORKING_DIR/generate-modulemap.sh"

# Success message
echo "Successfully generated Swift bindings, headers, and module map."
7 changes: 0 additions & 7 deletions components/suggest/build.rs

This file was deleted.

4 changes: 2 additions & 2 deletions components/suggest/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::rs::{DownloadedGlobalConfig, DownloadedWeatherData};

/// Global Suggest configuration data.
#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[derive(Clone, Default, Debug, Deserialize, Serialize, PartialEq, Eq, uniffi::Record)]
pub struct SuggestGlobalConfig {
pub show_less_frequently_cap: i32,
}
Expand All @@ -22,7 +22,7 @@ impl From<&DownloadedGlobalConfig> for SuggestGlobalConfig {
}

/// Per-provider configuration data.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, uniffi::Enum)]
pub enum SuggestProviderConfig {
Weather { min_keyword_length: i32 },
}
Expand Down
6 changes: 3 additions & 3 deletions components/suggest/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ pub impl<T> Result<T, rusqlite::Error> {

/// The error type for all Suggest component operations. These errors are
/// exposed to your application, which should handle them as needed.
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
#[non_exhaustive]
pub enum SuggestApiError {
#[error("Network error: {reason}")]
Network { reason: String },
// The server requested a backoff after too many requests
/// The server requested a backoff after too many requests
#[error("Backoff")]
Backoff { seconds: u64 },
// The application interrupted a request
/// An operation was interrupted by calling `SuggestStore.interrupt()`
#[error("Interrupted")]
Interrupted,
#[error("Other error: {reason}")]
Expand Down
10 changes: 6 additions & 4 deletions components/suggest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,16 @@ mod testing;
mod yelp;

pub use config::{SuggestGlobalConfig, SuggestProviderConfig};
pub use error::SuggestApiError;
pub use error::{Error, SuggestApiError};
pub use metrics::{LabeledTimingSample, SuggestIngestionMetrics};
pub use provider::{SuggestionProvider, SuggestionProviderConstraints};
pub use query::{QueryWithMetricsResult, SuggestionQuery};
pub use store::{InterruptKind, SuggestIngestionConstraints, SuggestStore, SuggestStoreBuilder};
pub use suggestion::{raw_suggestion_url_matches, Suggestion};

pub(crate) type Result<T> = std::result::Result<T, error::Error>;
pub type SuggestApiResult<T> = std::result::Result<T, error::SuggestApiError>;
pub(crate) type Result<T> = std::result::Result<T, Error>;
pub type SuggestApiResult<T> = std::result::Result<T, SuggestApiError>;

uniffi::include_scaffolding!("suggest");
uniffi::use_udl_record!(remote_settings, RemoteSettingsConfig);
uniffi::use_udl_enum!(remote_settings, RemoteSettingsServer);
uniffi::setup_scaffolding!();
8 changes: 6 additions & 2 deletions components/suggest/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
use std::time::Instant;

/// Single sample for a Glean labeled_timing_distribution
#[derive(uniffi::Record)]
pub struct LabeledTimingSample {
pub label: String,
pub value: u64, // time in microseconds
/// Time in microseconds
pub value: u64,
}

impl LabeledTimingSample {
Expand All @@ -19,9 +21,11 @@ impl LabeledTimingSample {
/// Ingestion metrics
///
/// These are recorded during [crate::Store::ingest] and returned to the consumer to record.
#[derive(Default)]
#[derive(Default, uniffi::Record)]
pub struct SuggestIngestionMetrics {
/// Samples for the `suggest.ingestion_time` metric
pub ingestion_times: Vec<LabeledTimingSample>,
/// Samples for the `suggest.ingestion_download_time` metric
pub download_times: Vec<LabeledTimingSample>,
}

Expand Down
9 changes: 7 additions & 2 deletions components/suggest/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub(crate) const DEFAULT_INGEST_PROVIDERS: [SuggestionProvider; 6] = [
];

/// A provider is a source of search suggestions.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, uniffi::Enum)]
#[repr(u8)]
pub enum SuggestionProvider {
Amp = 1,
Expand Down Expand Up @@ -121,7 +121,12 @@ impl ToSql for SuggestionProvider {
}
}

#[derive(Clone, Default, Debug)]
/// Some providers manage multiple suggestion subtypes. Queries, ingests, and
/// other operations on those providers must be constrained to a desired subtype.
#[derive(Clone, Default, Debug, uniffi::Record)]
pub struct SuggestionProviderConstraints {
/// `Exposure` provider - For each desired exposure suggestion type, this
/// should contain the value of the `suggestion_type` field of its remote
/// settings record(s).
pub exposure_suggestion_types: Option<Vec<String>>,
}
4 changes: 3 additions & 1 deletion components/suggest/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@
use crate::{LabeledTimingSample, Suggestion, SuggestionProvider, SuggestionProviderConstraints};

/// A query for suggestions to show in the address bar.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, uniffi::Record)]
pub struct SuggestionQuery {
pub keyword: String,
pub providers: Vec<SuggestionProvider>,
pub provider_constraints: Option<SuggestionProviderConstraints>,
pub limit: Option<i32>,
}

#[derive(uniffi::Record)]
pub struct QueryWithMetricsResult {
pub suggestions: Vec<Suggestion>,
/// Samples for the `suggest.query_time` metric
pub query_times: Vec<LabeledTimingSample>,
}

Expand Down
Loading

0 comments on commit 3f0066a

Please sign in to comment.