mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-04-22 16:17:23 +08:00
chore: update Rust to 1.95; replace cfg_if with cfg_select (#2121)
This commit is contained in:
@@ -52,17 +52,15 @@ runs:
|
|||||||
|
|
||||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: 1.95
|
||||||
target: ${{ !contains(inputs.target, 'mips') && inputs.target || '' }}
|
target: ${{ !contains(inputs.target, 'mips') && inputs.target || '' }}
|
||||||
|
components: ${{ contains(inputs.target, 'mips') && 'rust-src' || '' }}
|
||||||
cache: false
|
cache: false
|
||||||
rustflags: ''
|
rustflags: ''
|
||||||
|
|
||||||
- name: Install Rust (MIPS)
|
- name: Install Rust (MIPS)
|
||||||
if: ${{ contains(inputs.target, 'mips') }}
|
if: ${{ contains(inputs.target, 'mips') }}
|
||||||
run: |
|
run: |
|
||||||
rustup toolchain install nightly-2026-02-02-x86_64-unknown-linux-gnu
|
|
||||||
rustup component add rust-src --toolchain nightly-2026-02-02-x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
MUSL_TARGET=${{ inputs.target }}sf
|
MUSL_TARGET=${{ inputs.target }}sf
|
||||||
mkdir -p ./musl_gcc
|
mkdir -p ./musl_gcc
|
||||||
wget --inet4-only -c https://github.com/cross-tools/musl-cross/releases/download/20250520/${MUSL_TARGET}.tar.xz -P ./musl_gcc/
|
wget --inet4-only -c https://github.com/cross-tools/musl-cross/releases/download/20250520/${MUSL_TARGET}.tar.xz -P ./musl_gcc/
|
||||||
|
|||||||
@@ -191,8 +191,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Build (MIPS)
|
- name: Build (MIPS)
|
||||||
if: ${{ contains(matrix.TARGET, 'mips') }}
|
if: ${{ contains(matrix.TARGET, 'mips') }}
|
||||||
|
env:
|
||||||
|
RUSTC_BOOTSTRAP: 1
|
||||||
run: |
|
run: |
|
||||||
cargo +nightly-2026-02-02 build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc
|
cargo build -r --target $TARGET -Z build-std=std,panic_abort --package=easytier --features=jemalloc
|
||||||
|
|
||||||
- name: Compress
|
- name: Compress
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+3
-3
@@ -26,7 +26,7 @@ Thank you for your interest in contributing to EasyTier! This document provides
|
|||||||
#### Required Tools
|
#### Required Tools
|
||||||
- Node.js v21 or higher
|
- Node.js v21 or higher
|
||||||
- pnpm v9 or higher
|
- pnpm v9 or higher
|
||||||
- Rust toolchain (version 1.93)
|
- Rust toolchain (version 1.95)
|
||||||
- LLVM and Clang
|
- LLVM and Clang
|
||||||
- Protoc (Protocol Buffers compiler)
|
- Protoc (Protocol Buffers compiler)
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ sudo apt install -y bridge-utils
|
|||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
```bash
|
```bash
|
||||||
# Install Rust toolchain
|
# Install Rust toolchain
|
||||||
rustup install 1.93
|
rustup install 1.95
|
||||||
rustup default 1.93
|
rustup default 1.95
|
||||||
|
|
||||||
# Install project dependencies
|
# Install project dependencies
|
||||||
pnpm -r install
|
pnpm -r install
|
||||||
|
|||||||
+3
-3
@@ -34,7 +34,7 @@
|
|||||||
#### 必需工具
|
#### 必需工具
|
||||||
- Node.js v21 或更高版本
|
- Node.js v21 或更高版本
|
||||||
- pnpm v9 或更高版本
|
- pnpm v9 或更高版本
|
||||||
- Rust 工具链(版本 1.93)
|
- Rust 工具链(版本 1.95)
|
||||||
- LLVM 和 Clang
|
- LLVM 和 Clang
|
||||||
- Protoc(Protocol Buffers 编译器)
|
- Protoc(Protocol Buffers 编译器)
|
||||||
|
|
||||||
@@ -87,8 +87,8 @@ sudo apt install -y bridge-utils
|
|||||||
2. 安装依赖:
|
2. 安装依赖:
|
||||||
```bash
|
```bash
|
||||||
# 安装 Rust 工具链
|
# 安装 Rust 工具链
|
||||||
rustup install 1.93
|
rustup install 1.95
|
||||||
rustup default 1.93
|
rustup default 1.95
|
||||||
|
|
||||||
# 安装项目依赖
|
# 安装项目依赖
|
||||||
pnpm -r install
|
pnpm -r install
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ exclude = [
|
|||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.93.0"
|
rust-version = "1.95"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "unwind"
|
panic = "unwind"
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ time = "0.3"
|
|||||||
toml = "0.8.12"
|
toml = "0.8.12"
|
||||||
chrono = { version = "0.4.37", features = ["serde"] }
|
chrono = { version = "0.4.37", features = ["serde"] }
|
||||||
|
|
||||||
cfg-if = "1.0"
|
|
||||||
delegate = "0.13.5"
|
delegate = "0.13.5"
|
||||||
|
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ impl AclProcessor {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Sort by priority (higher priority first)
|
// Sort by priority (higher priority first)
|
||||||
rules.sort_by(|a, b| b.priority.cmp(&a.priority));
|
rules.sort_by_key(|r| std::cmp::Reverse(r.priority));
|
||||||
|
|
||||||
match chain.chain_type() {
|
match chain.chain_type() {
|
||||||
ChainType::Inbound => inbound_rules.extend(rules),
|
ChainType::Inbound => inbound_rules.extend(rules),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use base64::{Engine as _, prelude::BASE64_STANDARD};
|
use base64::{Engine as _, prelude::BASE64_STANDARD};
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use clap::ValueEnum;
|
use clap::ValueEnum;
|
||||||
use clap::builder::PossibleValue;
|
use clap::builder::PossibleValue;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -109,10 +108,9 @@ impl ValueEnum for EncryptionAlgorithm {
|
|||||||
#[allow(clippy::derivable_impls)]
|
#[allow(clippy::derivable_impls)]
|
||||||
impl Default for EncryptionAlgorithm {
|
impl Default for EncryptionAlgorithm {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
cfg_if! {
|
cfg_select! {
|
||||||
if #[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))] {
|
any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto") => EncryptionAlgorithm::AesGcm,
|
||||||
EncryptionAlgorithm::AesGcm
|
_ => {
|
||||||
} else {
|
|
||||||
crate::common::log::warn!("no AEAD encryption algorithm is available, using INSECURE XOR");
|
crate::common::log::warn!("no AEAD encryption algorithm is available, using INSECURE XOR");
|
||||||
EncryptionAlgorithm::Xor
|
EncryptionAlgorithm::Xor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use crate::common::get_logger_timer_rfc3339;
|
|||||||
use crate::common::tracing_rolling_appender::{FileAppenderWrapper, RollingFileAppenderBase};
|
use crate::common::tracing_rolling_appender::{FileAppenderWrapper, RollingFileAppenderBase};
|
||||||
use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
|
use crate::rpc_service::logger::{CURRENT_LOG_LEVEL, LOGGER_LEVEL_SENDER};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use cfg_if::cfg_if;
|
|
||||||
use paste::paste;
|
use paste::paste;
|
||||||
use std::io::IsTerminal;
|
use std::io::IsTerminal;
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
@@ -121,14 +120,13 @@ fn console_layers(default_level: Option<LevelFilter>) -> anyhow::Result<Vec<BoxL
|
|||||||
let (console_filter, _) =
|
let (console_filter, _) =
|
||||||
tracing_subscriber::reload::Layer::new(parse_env_filter(default_level)?);
|
tracing_subscriber::reload::Layer::new(parse_env_filter(default_level)?);
|
||||||
|
|
||||||
cfg_if! {
|
let (stdout, stderr) = cfg_select! {
|
||||||
if #[cfg(test)] {
|
test => {{
|
||||||
let w = tracing_subscriber::fmt::TestWriter::new;
|
let w = tracing_subscriber::fmt::TestWriter::new;
|
||||||
let (stdout, stderr) = (w, w);
|
(w, w)
|
||||||
} else {
|
}}
|
||||||
let (stdout, stderr) = (std::io::stdout, std::io::stderr);
|
_ => (std::io::stdout, std::io::stderr),
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
let ansi = std::io::stderr().is_terminal() || cfg!(test);
|
let ansi = std::io::stderr().is_terminal() || cfg!(test);
|
||||||
|
|
||||||
|
|||||||
+12
-24
@@ -239,15 +239,11 @@ impl StunClient {
|
|||||||
let mut mapped_addr = None;
|
let mut mapped_addr = None;
|
||||||
for x in msg.attributes() {
|
for x in msg.attributes() {
|
||||||
match x {
|
match x {
|
||||||
Attribute::MappedAddress(addr) => {
|
Attribute::MappedAddress(addr) if mapped_addr.is_none() => {
|
||||||
if mapped_addr.is_none() {
|
let _ = mapped_addr.insert(addr.address());
|
||||||
let _ = mapped_addr.insert(addr.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Attribute::XorMappedAddress(addr) => {
|
Attribute::XorMappedAddress(addr) if mapped_addr.is_none() => {
|
||||||
if mapped_addr.is_none() {
|
let _ = mapped_addr.insert(addr.address());
|
||||||
let _ = mapped_addr.insert(addr.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -259,15 +255,11 @@ impl StunClient {
|
|||||||
let mut changed_addr = None;
|
let mut changed_addr = None;
|
||||||
for x in msg.attributes() {
|
for x in msg.attributes() {
|
||||||
match x {
|
match x {
|
||||||
Attribute::OtherAddress(m) => {
|
Attribute::OtherAddress(m) if changed_addr.is_none() => {
|
||||||
if changed_addr.is_none() {
|
let _ = changed_addr.insert(m.address());
|
||||||
let _ = changed_addr.insert(m.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Attribute::ChangedAddress(m) => {
|
Attribute::ChangedAddress(m) if changed_addr.is_none() => {
|
||||||
if changed_addr.is_none() {
|
let _ = changed_addr.insert(m.address());
|
||||||
let _ = changed_addr.insert(m.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -714,15 +706,11 @@ impl TcpStunClient {
|
|||||||
let mut mapped_addr = None;
|
let mut mapped_addr = None;
|
||||||
for x in msg.attributes() {
|
for x in msg.attributes() {
|
||||||
match x {
|
match x {
|
||||||
Attribute::MappedAddress(addr) => {
|
Attribute::MappedAddress(addr) if mapped_addr.is_none() => {
|
||||||
if mapped_addr.is_none() {
|
let _ = mapped_addr.insert(addr.address());
|
||||||
let _ = mapped_addr.insert(addr.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Attribute::XorMappedAddress(addr) => {
|
Attribute::XorMappedAddress(addr) if mapped_addr.is_none() => {
|
||||||
if mapped_addr.is_none() {
|
let _ = mapped_addr.insert(addr.address());
|
||||||
let _ = mapped_addr.insert(addr.address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,9 +62,6 @@ pub fn create_encryptor(
|
|||||||
key_128: [u8; 16],
|
key_128: [u8; 16],
|
||||||
#[allow(unused_variables)] key_256: [u8; 32],
|
#[allow(unused_variables)] key_256: [u8; 32],
|
||||||
) -> Arc<dyn Encryptor> {
|
) -> Arc<dyn Encryptor> {
|
||||||
#[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))]
|
|
||||||
use cfg_if::cfg_if;
|
|
||||||
|
|
||||||
let algorithm = match EncryptionAlgorithm::try_from(algorithm) {
|
let algorithm = match EncryptionAlgorithm::try_from(algorithm) {
|
||||||
Ok(algorithm) => algorithm,
|
Ok(algorithm) => algorithm,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
@@ -83,44 +80,27 @@ pub fn create_encryptor(
|
|||||||
|
|
||||||
#[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))]
|
#[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))]
|
||||||
EncryptionAlgorithm::AesGcm => {
|
EncryptionAlgorithm::AesGcm => {
|
||||||
cfg_if! {
|
cfg_select! {
|
||||||
if #[cfg(feature = "openssl-crypto")] {
|
feature = "openssl-crypto" => Arc::new(openssl::OpenSslCipher::new_aes128_gcm(key_128)),
|
||||||
Arc::new(openssl::OpenSslCipher::new_aes128_gcm(key_128))
|
feature = "wireguard" => Arc::new(ring::RingCipher::new_aes128_gcm(key_128)),
|
||||||
} else if #[cfg(feature = "wireguard")] {
|
feature = "aes-gcm" => Arc::new(aes_gcm::AesGcmCipher::new_128(key_128)),
|
||||||
Arc::new(ring::RingCipher::new_aes128_gcm(key_128))
|
|
||||||
} else if #[cfg(feature = "aes-gcm")] {
|
|
||||||
Arc::new(aes_gcm::AesGcmCipher::new_128(key_128))
|
|
||||||
} else {
|
|
||||||
compile_error!("unreachable!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))]
|
#[cfg(any(feature = "aes-gcm", feature = "wireguard", feature = "openssl-crypto"))]
|
||||||
EncryptionAlgorithm::Aes256Gcm => {
|
EncryptionAlgorithm::Aes256Gcm => {
|
||||||
cfg_if! {
|
cfg_select! {
|
||||||
if #[cfg(feature = "openssl-crypto")] {
|
feature = "openssl-crypto" => Arc::new(openssl::OpenSslCipher::new_aes256_gcm(key_256)),
|
||||||
Arc::new(openssl::OpenSslCipher::new_aes256_gcm(key_256))
|
feature = "wireguard" => Arc::new(ring::RingCipher::new_aes256_gcm(key_256)),
|
||||||
} else if #[cfg(feature = "wireguard")] {
|
feature = "aes-gcm" => Arc::new(aes_gcm::AesGcmCipher::new_256(key_256)),
|
||||||
Arc::new(ring::RingCipher::new_aes256_gcm(key_256))
|
|
||||||
} else if #[cfg(feature = "aes-gcm")] {
|
|
||||||
Arc::new(aes_gcm::AesGcmCipher::new_256(key_256))
|
|
||||||
} else {
|
|
||||||
compile_error!("unreachable!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "wireguard", feature = "openssl-crypto"))]
|
#[cfg(any(feature = "wireguard", feature = "openssl-crypto"))]
|
||||||
EncryptionAlgorithm::ChaCha20 => {
|
EncryptionAlgorithm::ChaCha20 => {
|
||||||
cfg_if! {
|
cfg_select! {
|
||||||
if #[cfg(feature = "openssl-crypto")] {
|
feature = "openssl-crypto" => Arc::new(openssl::OpenSslCipher::new_chacha20(key_256)),
|
||||||
Arc::new(openssl::OpenSslCipher::new_chacha20(key_256))
|
feature = "wireguard" => Arc::new(ring::RingCipher::new_chacha20(key_256)),
|
||||||
} else if #[cfg(feature = "wireguard")] {
|
|
||||||
Arc::new(ring::RingCipher::new_chacha20(key_256))
|
|
||||||
} else {
|
|
||||||
compile_error!("unreachable!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4392,9 +4392,9 @@ mod tests {
|
|||||||
|
|
||||||
// find the smallest peer_id, which should be a center node
|
// find the smallest peer_id, which should be a center node
|
||||||
let mut all_route = [r_a.clone(), r_b.clone(), r_c.clone(), r_d.clone()];
|
let mut all_route = [r_a.clone(), r_b.clone(), r_c.clone(), r_d.clone()];
|
||||||
all_route.sort_by(|a, b| a.my_peer_id.cmp(&b.my_peer_id));
|
all_route.sort_by_key(|r| r.my_peer_id);
|
||||||
let mut all_peer_mgr = [p_a.clone(), p_b.clone(), p_c.clone(), p_d.clone()];
|
let mut all_peer_mgr = [p_a.clone(), p_b.clone(), p_c.clone(), p_d.clone()];
|
||||||
all_peer_mgr.sort_by_key(|a| a.my_peer_id());
|
all_peer_mgr.sort_by_key(|p| p.my_peer_id());
|
||||||
|
|
||||||
wait_for_condition(
|
wait_for_condition(
|
||||||
|| async { all_route[0].service_impl.sessions.len() == 3 },
|
|| async { all_route[0].service_impl.sessions.len() == 3 },
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ pub mod pnet;
|
|||||||
|
|
||||||
use std::{io, net::SocketAddr, sync::Arc};
|
use std::{io, net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_select! {
|
||||||
if #[cfg(target_os = "linux")] {
|
target_os = "linux" => {
|
||||||
pub mod linux_bpf;
|
pub mod linux_bpf;
|
||||||
|
|
||||||
pub fn create_tun(
|
pub fn create_tun(
|
||||||
@@ -26,7 +26,9 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if #[cfg(all(target_os = "macos", not(feature = "macos-ne")))] {
|
}
|
||||||
|
|
||||||
|
all(target_os = "macos", not(feature = "macos-ne")) => {
|
||||||
pub mod macos_bpf;
|
pub mod macos_bpf;
|
||||||
|
|
||||||
pub fn create_tun(
|
pub fn create_tun(
|
||||||
@@ -49,7 +51,9 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if #[cfg(all(windows, any(target_arch = "x86_64", target_arch = "x86")))] {
|
}
|
||||||
|
|
||||||
|
all(windows, any(target_arch = "x86_64", target_arch = "x86")) => {
|
||||||
pub mod windivert;
|
pub mod windivert;
|
||||||
|
|
||||||
pub fn create_tun(
|
pub fn create_tun(
|
||||||
@@ -72,7 +76,9 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
pub fn create_tun(
|
pub fn create_tun(
|
||||||
interface_name: &str,
|
interface_name: &str,
|
||||||
src_addr: Option<SocketAddr>,
|
src_addr: Option<SocketAddr>,
|
||||||
|
|||||||
Generated
+3
-3
@@ -48,11 +48,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1770174315,
|
"lastModified": 1776395632,
|
||||||
"narHash": "sha256-GUaMxDmJB1UULsIYpHtfblskVC6zymAaQ/Zqfo+13jc=",
|
"narHash": "sha256-Mi1uF5f2FsdBIvy+v7MtsqxD3Xjhd0ARJdwoqqqPtJo=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "095c394bb91342882f27f6c73f64064fb9de9f2a",
|
"rev": "8087ff1f47fff983a1fba70fa88b759f2fd8ae97",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -29,15 +29,15 @@
|
|||||||
allowUnfree = true;
|
allowUnfree = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
rustVersion = "1.93.0";
|
|
||||||
makeRust =
|
makeRust =
|
||||||
features:
|
features:
|
||||||
let
|
let
|
||||||
rustTarget = pkgs.stdenv.hostPlatform.config;
|
rustTarget = pkgs.stdenv.hostPlatform.config;
|
||||||
muslTarget = pkgs.lib.replaceStrings [ "gnu" ] [ "musl" ] rustTarget;
|
muslTarget = pkgs.lib.replaceStrings [ "gnu" ] [ "musl" ] rustTarget;
|
||||||
muslTargets = if pkgs.stdenv.isLinux then [ muslTarget ] else [ ];
|
muslTargets = if pkgs.stdenv.isLinux then [ muslTarget ] else [ ];
|
||||||
|
toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
||||||
in
|
in
|
||||||
pkgs.rust-bin.stable.${rustVersion}.default.override {
|
toolchain.override {
|
||||||
extensions = [
|
extensions = [
|
||||||
"rust-src"
|
"rust-src"
|
||||||
"rust-analyzer"
|
"rust-analyzer"
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.95"
|
||||||
|
profile = "minimal"
|
||||||
Reference in New Issue
Block a user