mirror of
https://github.com/mbilker/vgpu_unlock-rs.git
synced 2026-06-07 23:57:45 +02:00
lib: rework the configuration macros to make them more succinct
- Surprisingly, this ended up having more lines of code, but in my opinion the the code is cleaner.
This commit is contained in:
235
src/lib.rs
235
src/lib.rs
@@ -9,8 +9,8 @@
|
|||||||
//! configuration structure
|
//! configuration structure
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -540,77 +540,106 @@ fn apply_profile_override(
|
|||||||
vgpu_type: &str,
|
vgpu_type: &str,
|
||||||
config_override: &VgpuProfileOverride,
|
config_override: &VgpuProfileOverride,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
macro_rules! handle_copy_overrides {
|
macro_rules! patch_msg {
|
||||||
($source_field:ident => $target_field:ident) => {
|
($target_field:ident, $value:expr) => {
|
||||||
if let Some(value) = config_override.$source_field {
|
|
||||||
info!(
|
info!(
|
||||||
"Patching {}/{}: {} -> {}",
|
"Patching {}/{}: {} -> {}",
|
||||||
vgpu_type,
|
vgpu_type,
|
||||||
stringify!($target_field),
|
stringify!($target_field),
|
||||||
config.$target_field,
|
config.$target_field,
|
||||||
value
|
$value
|
||||||
);
|
);
|
||||||
|
|
||||||
config.$target_field = value;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
($field:ident) => {
|
($target_field:ident, $preprocess:ident, $value:expr) => {
|
||||||
handle_copy_overrides!($field => $field);
|
|
||||||
};
|
|
||||||
($($source_field:ident $(=> $target_field:ident)?),*$(,)?) => {
|
|
||||||
$(
|
|
||||||
handle_copy_overrides!($source_field $(=> $target_field)?);
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
macro_rules! handle_bool_overrides {
|
|
||||||
($source_field:ident => $target_field:ident) => {
|
|
||||||
if let Some(value) = config_override.$source_field {
|
|
||||||
let value = cmp::max(cmp::min(value, 0), 1);
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Patching {}/{}: {} -> {}",
|
"Patching {}/{}: {} -> {}",
|
||||||
vgpu_type,
|
vgpu_type,
|
||||||
stringify!($target_field),
|
stringify!($target_field),
|
||||||
config.$target_field,
|
$preprocess(&config.$target_field),
|
||||||
value
|
$value
|
||||||
);
|
);
|
||||||
|
|
||||||
config.$target_field = value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
($field:ident) => {
|
|
||||||
handle_bool_overrides!($field => $field);
|
|
||||||
};
|
|
||||||
($($source_field:ident $(=> $target_field:ident)?),*$(,)?) => {
|
|
||||||
$(
|
|
||||||
handle_bool_overrides!($source_field $(=> $target_field)?);
|
|
||||||
)*
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
macro_rules! handle_str_overrides {
|
macro_rules! error_too_long {
|
||||||
($source_field:ident => $target_field:ident) => {
|
($target_field:ident, $value:expr) => {
|
||||||
if let Some(value) = config_override.$source_field {
|
|
||||||
let value_bytes = value.as_bytes();
|
|
||||||
|
|
||||||
// Use `len - 1` to account for the required NULL terminator.
|
|
||||||
if value_bytes.len() > config.$target_field.len() - 1 {
|
|
||||||
error!(
|
error!(
|
||||||
"Patching {}/{}: value '{}' is too long",
|
"Patching {}/{}: value '{}' is too long",
|
||||||
vgpu_type,
|
vgpu_type,
|
||||||
stringify!($target_field),
|
stringify!($target_field),
|
||||||
value
|
$value
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! handle_override {
|
||||||
|
// Override entrypoint when the same field name is used as the source and target without
|
||||||
|
// an explicit `=>`.
|
||||||
|
(
|
||||||
|
class: $class:ident,
|
||||||
|
source_field: $field:ident,
|
||||||
|
) => {
|
||||||
|
handle_override! {
|
||||||
|
class: $class,
|
||||||
|
source_field: $field,
|
||||||
|
target_field: $field,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override entrypoint when both the source and target field names are defined explicitly.
|
||||||
|
(
|
||||||
|
class: $class:ident,
|
||||||
|
source_field: $source_field:ident,
|
||||||
|
target_field: $target_field:ident,
|
||||||
|
) => {
|
||||||
|
if let Some(value) = config_override.$source_field {
|
||||||
|
handle_override! {
|
||||||
|
class: $class,
|
||||||
|
value: value,
|
||||||
|
source_field: $source_field,
|
||||||
|
target_field: $target_field,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following are override handlers for each field class type (`bool`, `copy`, `str`,
|
||||||
|
// and `wide_str`).
|
||||||
|
(
|
||||||
|
class: bool,
|
||||||
|
value: $value:ident,
|
||||||
|
source_field: $source_field:ident,
|
||||||
|
target_field: $target_field:ident,
|
||||||
|
) => {
|
||||||
|
let $value = cmp::max(cmp::min($value, 0), 1);
|
||||||
|
|
||||||
|
patch_msg!($target_field, $value);
|
||||||
|
|
||||||
|
config.$target_field = $value;
|
||||||
|
};
|
||||||
|
(
|
||||||
|
class: copy,
|
||||||
|
value: $value:ident,
|
||||||
|
source_field: $source_field:ident,
|
||||||
|
target_field: $target_field:ident,
|
||||||
|
) => {
|
||||||
|
patch_msg!($target_field, $value);
|
||||||
|
|
||||||
|
config.$target_field = $value;
|
||||||
|
};
|
||||||
|
(
|
||||||
|
class: str,
|
||||||
|
value: $value:ident,
|
||||||
|
source_field: $source_field:ident,
|
||||||
|
target_field: $target_field:ident,
|
||||||
|
) => {
|
||||||
|
let value_bytes = $value.as_bytes();
|
||||||
|
|
||||||
|
// Use `len - 1` to account for the required NULL terminator.
|
||||||
|
if value_bytes.len() > config.$target_field.len() - 1 {
|
||||||
|
error_too_long!($target_field, $value);
|
||||||
} else {
|
} else {
|
||||||
info!(
|
patch_msg!($target_field, from_c_str, $value);
|
||||||
"Patching {}/{}: '{}' -> '{}'",
|
|
||||||
vgpu_type,
|
|
||||||
stringify!($target_field),
|
|
||||||
from_c_str(&config.$target_field),
|
|
||||||
value
|
|
||||||
);
|
|
||||||
|
|
||||||
// Zero out the field first.
|
// Zero out the field first.
|
||||||
// (`fill` was stabilized in Rust 1.50, but Debian Bullseye ships with 1.48)
|
// (`fill` was stabilized in Rust 1.50, but Debian Bullseye ships with 1.48)
|
||||||
@@ -621,38 +650,18 @@ fn apply_profile_override(
|
|||||||
// Write the string bytes.
|
// Write the string bytes.
|
||||||
let _ = config.$target_field[..].as_mut().write_all(value_bytes);
|
let _ = config.$target_field[..].as_mut().write_all(value_bytes);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
($field:ident) => {
|
(
|
||||||
handle_str_overrides!($field => $field);
|
class: wide_str,
|
||||||
};
|
value: $value:ident,
|
||||||
($($source_field:ident $(=> $target_field:ident)?),*$(,)?) => {
|
source_field: $source_field:ident,
|
||||||
$(
|
target_field: $target_field:ident,
|
||||||
handle_str_overrides!($source_field $(=> $target_field)?);
|
) => {
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
macro_rules! handle_wide_str_overrides {
|
|
||||||
($source_field:ident => $target_field:ident) => {
|
|
||||||
if let Some(value) = config_override.$source_field {
|
|
||||||
// Use `len - 1` to account for the required NULL terminator.
|
// Use `len - 1` to account for the required NULL terminator.
|
||||||
if value.encode_utf16().count() > config.$target_field.len() - 1 {
|
if $value.encode_utf16().count() > config.$target_field.len() - 1 {
|
||||||
error!(
|
error_too_long!($target_field, $value);
|
||||||
"Patching {}/{}: value '{}' is too long",
|
|
||||||
vgpu_type,
|
|
||||||
stringify!($target_field),
|
|
||||||
value
|
|
||||||
);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
info!(
|
patch_msg!($target_field, WideCharFormat, $value);
|
||||||
"Patching {}/{}: '{}' -> '{}'",
|
|
||||||
vgpu_type,
|
|
||||||
stringify!($target_field),
|
|
||||||
WideCharFormat(&config.$target_field),
|
|
||||||
value
|
|
||||||
);
|
|
||||||
|
|
||||||
// Zero out the field first.
|
// Zero out the field first.
|
||||||
// (`fill` was stabilized in Rust 1.50, but Debian Bullseye ships with 1.48)
|
// (`fill` was stabilized in Rust 1.50, but Debian Bullseye ships with 1.48)
|
||||||
@@ -663,53 +672,62 @@ fn apply_profile_override(
|
|||||||
// Write the string bytes.
|
// Write the string bytes.
|
||||||
for (v, ch) in config.$target_field[..]
|
for (v, ch) in config.$target_field[..]
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(value.encode_utf16().chain(Some(0)))
|
.zip($value.encode_utf16().chain(Some(0)))
|
||||||
{
|
{
|
||||||
*v = ch;
|
*v = ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
macro_rules! handle_overrides {
|
||||||
($field:ident) => {
|
(
|
||||||
handle_wide_str_overrides!($field => $field);
|
$($class:ident: [
|
||||||
};
|
$($source_field:ident $(=> $target_field:ident)?),*$(,)?
|
||||||
($($source_field:ident $(=> $target_field:ident)?),*$(,)?) => {
|
]),*$(,)?
|
||||||
|
) => {
|
||||||
$(
|
$(
|
||||||
handle_wide_str_overrides!($source_field $(=> $target_field)?);
|
$(
|
||||||
|
handle_override! {
|
||||||
|
class: $class,
|
||||||
|
source_field: $source_field,
|
||||||
|
$(target_field: $target_field,)?
|
||||||
|
}
|
||||||
|
)*
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// While the following could be done with two statements. I wanted the log statements to be in
|
// While the following could be done with fewer branches, I wanted the log statements to be in
|
||||||
// field order.
|
// field order.
|
||||||
|
|
||||||
handle_copy_overrides! {
|
handle_overrides! {
|
||||||
|
copy: [
|
||||||
gpu_type => vgpu_type,
|
gpu_type => vgpu_type,
|
||||||
}
|
],
|
||||||
handle_str_overrides! {
|
str: [
|
||||||
card_name => vgpu_name,
|
card_name => vgpu_name,
|
||||||
vgpu_type => vgpu_class,
|
vgpu_type => vgpu_class,
|
||||||
features,
|
features,
|
||||||
}
|
],
|
||||||
handle_copy_overrides! {
|
copy: [
|
||||||
max_instances,
|
max_instances,
|
||||||
num_displays => num_heads,
|
num_displays => num_heads,
|
||||||
display_width => max_resolution_x,
|
display_width => max_resolution_x,
|
||||||
display_height => max_resolution_y,
|
display_height => max_resolution_y,
|
||||||
max_pixels,
|
max_pixels,
|
||||||
frl_config,
|
frl_config,
|
||||||
}
|
],
|
||||||
handle_bool_overrides! {
|
bool: [
|
||||||
cuda_enabled,
|
cuda_enabled,
|
||||||
ecc_supported,
|
ecc_supported,
|
||||||
}
|
],
|
||||||
handle_copy_overrides! {
|
copy: [
|
||||||
mig_instance_size,
|
mig_instance_size,
|
||||||
}
|
],
|
||||||
handle_bool_overrides! {
|
bool: [
|
||||||
multi_vgpu_supported,
|
multi_vgpu_supported,
|
||||||
}
|
],
|
||||||
handle_copy_overrides! {
|
copy: [
|
||||||
pci_id => vdev_id,
|
pci_id => vdev_id,
|
||||||
pci_device_id => pdev_id,
|
pci_device_id => pdev_id,
|
||||||
framebuffer => fb_length,
|
framebuffer => fb_length,
|
||||||
@@ -717,19 +735,20 @@ fn apply_profile_override(
|
|||||||
framebuffer_reservation => fb_reservation,
|
framebuffer_reservation => fb_reservation,
|
||||||
encoder_capacity,
|
encoder_capacity,
|
||||||
bar1_length,
|
bar1_length,
|
||||||
}
|
],
|
||||||
handle_bool_overrides! {
|
bool: [
|
||||||
frl_enabled => frl_enable,
|
frl_enabled => frl_enable,
|
||||||
}
|
],
|
||||||
handle_str_overrides! {
|
str: [
|
||||||
adapter_name,
|
adapter_name,
|
||||||
}
|
],
|
||||||
handle_wide_str_overrides! {
|
wide_str: [
|
||||||
adapter_name => adapter_name_unicode,
|
adapter_name => adapter_name_unicode,
|
||||||
}
|
],
|
||||||
handle_str_overrides! {
|
str: [
|
||||||
short_gpu_name => short_gpu_name_string,
|
short_gpu_name => short_gpu_name_string,
|
||||||
license_type => licensed_product_name,
|
license_type => licensed_product_name,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|||||||
Reference in New Issue
Block a user