*: Install rust and cargo when running presubmit.sh

Update the rustfmt version to match downstream.
Format existing code with `cargo fmt` to pass presubmit.

Bug: b/439013538
Change-Id: Iabb97123b6929378e54c568bc37450d15fef73a1
Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/2781
Reviewed-by: Marie Janssen <jamuraa@google.com>
Commit-Queue: Dayeong Lee <dayeonglee@google.com>
diff --git a/.gitignore b/.gitignore
index f4fd39f..8bcc936 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 # Vim swap files.
 *.swp
+
+# CIPD files.
+infra/packages
diff --git a/infra/cipd.ensure b/infra/cipd.ensure
new file mode 100644
index 0000000..03d9b0c
--- /dev/null
+++ b/infra/cipd.ensure
@@ -0,0 +1,15 @@
+$VerifiedPlatform linux-amd64
+$VerifiedPlatform mac-amd64
+$ParanoidMode CheckPresence
+
+# LLVM.
+fuchsia/third_party/clang/${platform} git_revision:3576f05db125006ffbe22bfc199a269bf2a4a06f
+fuchsia/third_party/gcc/${os=linux}-amd64 git_revision:52a883ddece2f70a67aa37c9170bfa22253ae2c4,98583463abed11c7659028c0d68a9619fed5f559
+fuchsia/third_party/gcc/${os=mac}-amd64 git_revision:fbe5e908de76aa240bbcd2f144c156eccc863604,25558d2fc0e8b77d4c522c322012b048db4c1485
+
+# Rust.
+fuchsia/third_party/rust/host/${platform} git_revisions:afa859f8121bf2985362a2c8414dc71a825ccf2d,03b0f55d9c6319a851a60bb084faca0e32a38f2b
+fuchsia/third_party/rust/target/x86_64-unknown-linux-gnu git_revisions:afa859f8121bf2985362a2c8414dc71a825ccf2d,03b0f55d9c6319a851a60bb084faca0e32a38f2b
+fuchsia/third_party/rust/target/thumbv7m-none-eabi git_revisions:afa859f8121bf2985362a2c8414dc71a825ccf2d,03b0f55d9c6319a851a60bb084faca0e32a38f2b
+@Subdir rust_bindgen
+fuchsia/third_party/rust_bindgen/${platform} git_revision:f518815cc14a7f8c292964bb37179a1070d7e18a
diff --git a/infra/env_setup.sh b/infra/env_setup.sh
new file mode 100644
index 0000000..ab8aafc
--- /dev/null
+++ b/infra/env_setup.sh
@@ -0,0 +1,23 @@
+# No "#!" line. This script should be sourced, not executed.
+
+# set -o errexit  # Exit on errors.
+# set -o nounset  # Error on unset variables.
+# set -o xtrace  # Print commands.
+
+_abspath () {
+  $(command -v python3 || command -v python) -c "import os.path; print(os.path.abspath('$@'))"
+}
+
+export INFRA=$(dirname $(_abspath "$BASH_SOURCE"))
+
+cipd ensure -ensure-file "$INFRA/cipd.ensure" -root "$INFRA/packages"
+
+export PATH="$INFRA/packages/bin:$INFRA/packages:$PATH"
+
+if [[ "$(uname -m)" == "x86_64" ]]; then
+  ln -sf $INFRA/packages/bin/x86_64-elf-gcc $INFRA/packages/bin/cc
+  ln -sf $INFRA/packages/bin/x86_64-elf-gcc $INFRA/packages/bin/gcc
+else
+  ln -sf $INFRA/packages/bin/aarch64-elf-gcc $INFRA/packages/bin/cc
+  ln -sf $INFRA/packages/bin/aarch64-elf-gcc $INFRA/packages/bin/gcc
+fi
diff --git a/presubmit.sh b/presubmit.sh
index 3da037b..f05c74a 100755
--- a/presubmit.sh
+++ b/presubmit.sh
@@ -1,8 +1,27 @@
 #!/bin/bash
 # Presubmit script for CI/CD
 
-# Exit on error, print commands, and exit on unset variables.
-set -eux
+# Exit on error, and exit on unset variables.
+set -o errexit
+set -o nounset
+
+# Create .cargo/config.toml for the musl target
+# TODO: add a line for mac.
+BASE_DIR=$(dirname "$0")
+mkdir -p "$BASE_DIR/.cargo"
+cat > "$BASE_DIR/.cargo/config.toml" <<EOL
+[target.x86_64-unknown-linux-musl]
+rustflags = ["-C", "linker=clang", "-C", "link-arg=-fuse-ld=lld"]
+
+[target.x86_64-unknown-linux-gnu]
+rustflags = ["-C", "linker=clang", "-C", "link-arg=-fuse-ld=lld"]
+EOL
+
+# Install tools.
+. "$(dirname "$0")/infra/env_setup.sh"
+
+# Print commands as they're executed.
+set -o xtrace
 
 # Change to the rust directory to run cargo commands.
 cd "$(dirname "$0")/rust"
@@ -14,11 +33,16 @@
 # 2. Check formatting.
 # `cargo fmt -- --check` will exit with a non-zero status code if any
 # files are not formatted correctly.
-cargo fmt -- --check
+if ! cargo fmt -- --check; then
+    { set +x; } 2>/dev/null
+    echo "Please run \`cargo fmt\` to format your code"
+    exit 1
+fi
+
 
 # 3. Run tests.
 # `set -e` will cause the script to exit if any tests fail.
 cargo test
 
 { set +x; } 2>/dev/null
-echo "Presubmit checks passed!";
+echo "Presubmit checks passed!"
diff --git a/rust/bt-ascs/src/types.rs b/rust/bt-ascs/src/types.rs
index fd6014d..ce5a579 100644
--- a/rust/bt-ascs/src/types.rs
+++ b/rust/bt-ascs/src/types.rs
@@ -546,7 +546,11 @@
     type Error = bt_common::packet_encoding::Error;
 
     fn try_from(value: u8) -> Result<Self, Self::Error> {
-        if value > 0xEF { Err(Self::Error::OutOfRange) } else { Ok(CigId(value)) }
+        if value > 0xEF {
+            Err(Self::Error::OutOfRange)
+        } else {
+            Ok(CigId(value))
+        }
     }
 }
 
@@ -567,7 +571,11 @@
     type Error = bt_common::packet_encoding::Error;
 
     fn try_from(value: u8) -> Result<Self, Self::Error> {
-        if value > 0xEF { Err(Self::Error::OutOfRange) } else { Ok(CisId(value)) }
+        if value > 0xEF {
+            Err(Self::Error::OutOfRange)
+        } else {
+            Ok(CisId(value))
+        }
     }
 }
 
diff --git a/rust/bt-bass/src/types.rs b/rust/bt-bass/src/types.rs
index 3f8e2d3..70c97ad 100644
--- a/rust/bt-bass/src/types.rs
+++ b/rust/bt-bass/src/types.rs
@@ -1340,10 +1340,8 @@
             broadcast_id: BroadcastId::try_from(0x00010203).unwrap(),
             pa_sync_state: PaSyncState::NotSynced,
             big_encryption: EncryptionStatus::NotEncrypted,
-            subgroups: vec![
-                BigSubgroup::new(None)
-                    .with_metadata(vec![Metadata::ParentalRating(Rating::AllAge)]), /* encoded_len = 8 */
-            ],
+            subgroups: vec![BigSubgroup::new(None)
+                .with_metadata(vec![Metadata::ParentalRating(Rating::AllAge)]) /* encoded_len = 8 */],
         });
         assert_eq!(state.encoded_len(), 23);
         let mut buf = vec![0; state.encoded_len()];
diff --git a/rust/bt-common/src/generic_audio/codec_capabilities.rs b/rust/bt-common/src/generic_audio/codec_capabilities.rs
index a5c23a5..5386d78 100644
--- a/rust/bt-common/src/generic_audio/codec_capabilities.rs
+++ b/rust/bt-common/src/generic_audio/codec_capabilities.rs
@@ -163,9 +163,11 @@
     fn encode_value(&self, buf: &mut [u8]) -> Result<(), crate::packet_encoding::Error> {
         match self {
             CodecCapability::SupportedAudioChannelCounts(counts) => {
-                buf[0] = counts
-                    .iter()
-                    .fold(0, |acc, count| if *count > 8 { acc } else { acc | (1 << (*count - 1)) });
+                buf[0] =
+                    counts.iter().fold(
+                        0,
+                        |acc, count| if *count > 8 { acc } else { acc | (1 << (*count - 1)) },
+                    );
             }
             CodecCapability::SupportedFrameDurations(support) => {
                 buf[0] = match support {
diff --git a/rust/bt-pacs/src/server.rs b/rust/bt-pacs/src/server.rs
index e2f185f..c3bfa1a 100644
--- a/rust/bt-pacs/src/server.rs
+++ b/rust/bt-pacs/src/server.rs
@@ -135,7 +135,11 @@
 
 impl<T: bt_gatt::ServerTypes> LocalServiceState<T> {
     fn is_published(&self) -> bool {
-        if let LocalServiceState::NotPublished { .. } = self { false } else { true }
+        if let LocalServiceState::NotPublished { .. } = self {
+            false
+        } else {
+            true
+        }
     }
 }
 
@@ -499,46 +503,37 @@
     #[test]
     fn build_server_error() {
         // No sink or source PACs.
-        assert!(
-            ServerBuilder::new()
-                .build::<FakeTypes>(
-                    AudioContexts::new(
-                        HashSet::from([ContextType::Conversational, ContextType::Media]),
-                        HashSet::from([ContextType::Media]),
-                    ),
-                    AudioContexts::new(HashSet::from([ContextType::Media]), HashSet::new()),
-                )
-                .is_err()
-        );
+        assert!(ServerBuilder::new()
+            .build::<FakeTypes>(
+                AudioContexts::new(
+                    HashSet::from([ContextType::Conversational, ContextType::Media]),
+                    HashSet::from([ContextType::Media]),
+                ),
+                AudioContexts::new(HashSet::from([ContextType::Media]), HashSet::new()),
+            )
+            .is_err());
 
         // Sink audio context in available not in supported.
-        assert!(
-            default_server_builder()
-                .build::<FakeTypes>(
-                    AudioContexts::new(
-                        HashSet::from([ContextType::Conversational, ContextType::Media]),
-                        HashSet::from([ContextType::Media]),
-                    ),
-                    AudioContexts::new(HashSet::from([ContextType::Alerts]), HashSet::new()),
-                )
-                .is_err()
-        );
+        assert!(default_server_builder()
+            .build::<FakeTypes>(
+                AudioContexts::new(
+                    HashSet::from([ContextType::Conversational, ContextType::Media]),
+                    HashSet::from([ContextType::Media]),
+                ),
+                AudioContexts::new(HashSet::from([ContextType::Alerts]), HashSet::new()),
+            )
+            .is_err());
 
         // Sink audio context in available not in supported.
-        assert!(
-            default_server_builder()
-                .build::<FakeTypes>(
-                    AudioContexts::new(
-                        HashSet::from([ContextType::Conversational, ContextType::Media]),
-                        HashSet::from([ContextType::Media]),
-                    ),
-                    AudioContexts::new(
-                        HashSet::from([]),
-                        HashSet::from([ContextType::EmergencyAlarm])
-                    ),
-                )
-                .is_err()
-        );
+        assert!(default_server_builder()
+            .build::<FakeTypes>(
+                AudioContexts::new(
+                    HashSet::from([ContextType::Conversational, ContextType::Media]),
+                    HashSet::from([ContextType::Media]),
+                ),
+                AudioContexts::new(HashSet::from([]), HashSet::from([ContextType::EmergencyAlarm])),
+            )
+            .is_err());
     }
 
     #[test]
diff --git a/rust/rustfmt.toml b/rust/rustfmt.toml
index 71b39c8..61b5ed3 100644
--- a/rust/rustfmt.toml
+++ b/rust/rustfmt.toml
@@ -1,7 +1,5 @@
 # rustfmt which matches most of our downstream
-
-edition = "2021"
-version = "Two"
+edition = "2024"
 
 # The "Default" setting has a heuristic which splits lines too aggresively.
 # We are willing to revisit this setting in future versions of rustfmt.