forked from 1b-agent/opencadstudio-upstream
Snapshot: V4 plugin API and host integration
This commit is contained in:
1 parent
448869ac35
commit
29c41a4041
36 files changed
+5463
-253
No files matched your search
@@ -4,14 +4,21 @@
|
||||
/// compatibility. v2 added `HostApi::start_interactive`. v3 changes
|
||||
/// `document()` / `document_mut()` to local cached copies for out-of-process
|
||||
/// plugins and appends `document_reader` / `document_view` at the end of the
|
||||
/// vtable so API v2 plugins keep working.
|
||||
pub const API_VERSION: u32 = 3;
|
||||
/// vtable so API v2 plugins keep working. v4 adds full-duplex notifications on
|
||||
/// a multiplexed socket while leaving the V2/V3 ABI and protocol untouched.
|
||||
pub const API_VERSION: u32 = 4;
|
||||
|
||||
/// Oldest plugin API major the current host still loads. This keeps previously
|
||||
/// compiled cdylibs usable as long as their vtable layout is a prefix of the
|
||||
/// current `HostApi` trait.
|
||||
pub const API_VERSION_MIN_SUPPORTED: u32 = 2;
|
||||
|
||||
/// Environment variable that caps the API major accepted by the host at
|
||||
/// runtime. Set to `3` to disable V4 plugins while keeping V2/V3 plugins
|
||||
/// working; set to `2` for V2-only mode. The same mechanism will apply to
|
||||
/// future API majors.
|
||||
pub const MAX_API_VERSION_ENV: &str = "OCS_PLUGIN_MAX_API_VERSION";
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct ApiVersion {
|
||||
pub major: u32,
|
||||
@@ -28,17 +35,33 @@ impl ApiVersion {
|
||||
}
|
||||
}
|
||||
|
||||
/// The effective maximum API major this host accepts, honoring
|
||||
/// [`MAX_API_VERSION_ENV`]. This lets operators disable a new API major at
|
||||
/// runtime without rebuilding.
|
||||
pub fn effective_max_api_version() -> u32 {
|
||||
std::env::var(MAX_API_VERSION_ENV)
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.map(|max: u32| max.clamp(API_VERSION_MIN_SUPPORTED, API_VERSION))
|
||||
.unwrap_or(API_VERSION)
|
||||
}
|
||||
|
||||
/// True when a plugin built against `plugin_major` can be loaded by this host.
|
||||
/// The host supports majors from `API_VERSION_MIN_SUPPORTED` up to
|
||||
/// `API_VERSION`.
|
||||
/// [`effective_max_api_version`], which can be lowered at runtime via
|
||||
/// `OCS_PLUGIN_MAX_API_VERSION`.
|
||||
pub fn host_accepts_plugin_version(plugin_major: u32) -> bool {
|
||||
plugin_major >= API_VERSION_MIN_SUPPORTED && plugin_major <= API_VERSION
|
||||
plugin_major >= API_VERSION_MIN_SUPPORTED && plugin_major <= effective_max_api_version()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Mutex;
|
||||
|
||||
use super::*;
|
||||
|
||||
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
#[test]
|
||||
fn current_matches_const() {
|
||||
assert_eq!(ApiVersion::CURRENT.major, API_VERSION);
|
||||
@@ -61,6 +84,55 @@ mod tests {
|
||||
fn api_v2_plugin_runs_on_api_v3_host() {
|
||||
assert!(ApiVersion { major: 2 }.is_compatible_with(ApiVersion { major: 3 }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_max_defaults_to_api_version() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
assert_eq!(effective_max_api_version(), API_VERSION);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_max_can_disable_v4() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::set_var(MAX_API_VERSION_ENV, "3");
|
||||
assert_eq!(effective_max_api_version(), 3);
|
||||
assert!(!host_accepts_plugin_version(4));
|
||||
assert!(host_accepts_plugin_version(3));
|
||||
assert!(host_accepts_plugin_version(2));
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_max_v2_only_mode() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::set_var(MAX_API_VERSION_ENV, "2");
|
||||
assert_eq!(effective_max_api_version(), 2);
|
||||
assert!(!host_accepts_plugin_version(4));
|
||||
assert!(!host_accepts_plugin_version(3));
|
||||
assert!(host_accepts_plugin_version(2));
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effective_max_clamps_to_supported_range() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::set_var(MAX_API_VERSION_ENV, "99");
|
||||
assert_eq!(effective_max_api_version(), API_VERSION);
|
||||
std::env::set_var(MAX_API_VERSION_ENV, "1");
|
||||
assert_eq!(effective_max_api_version(), API_VERSION_MIN_SUPPORTED);
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn host_accepts_supported_range() {
|
||||
let _guard = ENV_LOCK.lock().unwrap();
|
||||
std::env::remove_var(MAX_API_VERSION_ENV);
|
||||
assert!(host_accepts_plugin_version(API_VERSION_MIN_SUPPORTED));
|
||||
assert!(host_accepts_plugin_version(API_VERSION));
|
||||
assert!(!host_accepts_plugin_version(API_VERSION + 1));
|
||||
assert!(!host_accepts_plugin_version(API_VERSION_MIN_SUPPORTED - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/// Static metadata every plugin supplies at registration time.
|
||||
|
||||
Reference in new issue
Block a user