fda35dd8ce
* feat: add duration filtering for similar songs matching Signed-off-by: Deluan <deluan@navidrome.org> * test: refactor expectations for similar songs in provider matching tests Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add functions to retrieve similar songs by track, album, and artist Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): support uint32 in ndpgen Signed-off-by: Deluan <deluan@navidrome.org> * fix(plugins): update duration field to use seconds as float instead of milliseconds as uint32 Signed-off-by: Deluan <deluan@navidrome.org> * fix: add helper functions for Rust's skip_serializing_if with numeric types Signed-off-by: Deluan <deluan@navidrome.org> * feat(provider): enhance track matching logic to fallback to title match when duration-filtered tracks fail --------- Signed-off-by: Deluan <deluan@navidrome.org>
199 lines
7.1 KiB
Cheetah
199 lines
7.1 KiB
Cheetah
// Code generated by ndpgen. DO NOT EDIT.
|
|
//
|
|
// This file contains export wrappers for the {{.Capability.Interface}} capability.
|
|
// It is intended for use in Navidrome plugins built with extism-pdk.
|
|
{{if .Capability.Structs}}
|
|
use serde::{Deserialize, Serialize};
|
|
{{- if hasHashMap .Capability}}
|
|
use std::collections::HashMap;
|
|
{{- end}}
|
|
|
|
// Helper functions for skip_serializing_if with numeric types
|
|
#[allow(dead_code)]
|
|
fn is_zero_i32(value: &i32) -> bool { *value == 0 }
|
|
#[allow(dead_code)]
|
|
fn is_zero_u32(value: &u32) -> bool { *value == 0 }
|
|
#[allow(dead_code)]
|
|
fn is_zero_i64(value: &i64) -> bool { *value == 0 }
|
|
#[allow(dead_code)]
|
|
fn is_zero_u64(value: &u64) -> bool { *value == 0 }
|
|
#[allow(dead_code)]
|
|
fn is_zero_f32(value: &f32) -> bool { *value == 0.0 }
|
|
#[allow(dead_code)]
|
|
fn is_zero_f64(value: &f64) -> bool { *value == 0.0 }
|
|
{{- end}}
|
|
|
|
{{- /* Generate type alias definitions */ -}}
|
|
{{- range .Capability.TypeAliases}}
|
|
|
|
{{- if .Doc}}
|
|
{{rustDocComment .Doc}}
|
|
{{- end}}
|
|
pub type {{.Name}} = {{rustTypeAlias .Type}};
|
|
{{- end}}
|
|
|
|
{{- /* Generate const definitions */ -}}
|
|
{{- range .Capability.Consts}}
|
|
{{- if .Values}}
|
|
{{- $type := .Type}}
|
|
{{- range $i, $v := .Values}}
|
|
|
|
{{- if $v.Doc}}
|
|
{{rustDocComment $v.Doc}}
|
|
{{- end}}
|
|
{{- /* Use the type alias name if a named type is provided, otherwise use &'static str */ -}}
|
|
{{- if $type}}
|
|
pub const {{rustConstName $v.Name}}: {{$type}} = {{$v.Value}};
|
|
{{- else}}
|
|
pub const {{rustConstName $v.Name}}: &'static str = {{$v.Value}};
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- end}}
|
|
{{- end}}
|
|
|
|
{{- /* Generate struct definitions */ -}}
|
|
{{- range .Capability.Structs}}
|
|
|
|
{{- if .Doc}}
|
|
{{rustDocComment .Doc}}
|
|
{{- else}}
|
|
/// {{.Name}} represents the {{.Name}} data structure.
|
|
{{- end}}
|
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct {{.Name}} {
|
|
{{- range .Fields}}
|
|
{{- if .Doc}}
|
|
{{rustDocComment .Doc | indent 4}}
|
|
{{- end}}
|
|
{{- if .OmitEmpty}}
|
|
#[serde(default, skip_serializing_if = "{{skipSerializingFunc .Type}}")]
|
|
{{- else}}
|
|
#[serde(default)]
|
|
{{- end}}
|
|
pub {{rustFieldName .Name}}: {{fieldRustType .}},
|
|
{{- end}}
|
|
}
|
|
{{- end}}
|
|
|
|
/// Error represents an error from a capability method.
|
|
#[derive(Debug)]
|
|
pub struct Error {
|
|
pub message: String,
|
|
}
|
|
|
|
impl std::fmt::Display for Error {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.message)
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for Error {}
|
|
|
|
impl Error {
|
|
pub fn new(message: impl Into<String>) -> Self {
|
|
Self { message: message.into() }
|
|
}
|
|
}
|
|
|
|
{{- /* Generate main interface based on required flag */ -}}
|
|
{{if .Capability.Required}}
|
|
|
|
/// {{agentName .Capability}} requires all methods to be implemented.
|
|
{{- if .Capability.Doc}}
|
|
{{rustDocComment .Capability.Doc}}
|
|
{{- end}}
|
|
pub trait {{agentName .Capability}} {
|
|
{{- range .Capability.Methods}}
|
|
/// {{.Name}}{{if .Doc}} - {{.Doc}}{{end}}
|
|
{{- if and .HasInput .HasOutput}}
|
|
fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<{{rustOutputType .Output.Type}}, Error>;
|
|
{{- else if .HasInput}}
|
|
fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<(), Error>;
|
|
{{- else if .HasOutput}}
|
|
fn {{rustMethodName .Name}}(&self) -> Result<{{rustOutputType .Output.Type}}, Error>;
|
|
{{- else}}
|
|
fn {{rustMethodName .Name}}(&self) -> Result<(), Error>;
|
|
{{- end}}
|
|
{{- end}}
|
|
}
|
|
|
|
/// Register all exports for the {{agentName .Capability}} capability.
|
|
/// This macro generates the WASM export functions for all trait methods.
|
|
#[macro_export]
|
|
macro_rules! register_{{snakeCase .Package}} {
|
|
($plugin_type:ty) => {
|
|
{{- range .Capability.Methods}}
|
|
#[extism_pdk::plugin_fn]
|
|
pub fn {{.ExportName}}(
|
|
{{- if .HasInput}}
|
|
req: extism_pdk::Json<$crate::{{snakeCase $.Package}}::{{rustOutputType .Input.Type}}>
|
|
{{- end}}
|
|
) -> extism_pdk::FnResult<{{if .HasOutput}}extism_pdk::Json<{{if isPrimitiveRust .Output.Type}}{{rustOutputType .Output.Type}}{{else}}$crate::{{snakeCase $.Package}}::{{rustOutputType .Output.Type}}{{end}}>{{else}}(){{end}}> {
|
|
let plugin = <$plugin_type>::default();
|
|
{{- if and .HasInput .HasOutput}}
|
|
let result = $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
|
|
Ok(extism_pdk::Json(result))
|
|
{{- else if .HasInput}}
|
|
$crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
|
|
Ok(())
|
|
{{- else if .HasOutput}}
|
|
let result = $crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin)?;
|
|
Ok(extism_pdk::Json(result))
|
|
{{- else}}
|
|
$crate::{{snakeCase $.Package}}::{{agentName $.Capability}}::{{rustMethodName .Name}}(&plugin)?;
|
|
Ok(())
|
|
{{- end}}
|
|
}
|
|
{{- end}}
|
|
};
|
|
}
|
|
{{- else}}
|
|
|
|
{{- /* Generate optional provider interfaces for non-required capabilities */ -}}
|
|
{{- range .Capability.Methods}}
|
|
|
|
/// {{providerInterface .}} provides the {{.Name}} function.
|
|
pub trait {{providerInterface .}} {
|
|
{{- if and .HasInput .HasOutput}}
|
|
fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<{{rustOutputType .Output.Type}}, Error>;
|
|
{{- else if .HasInput}}
|
|
fn {{rustMethodName .Name}}(&self, req: {{rustOutputType .Input.Type}}) -> Result<(), Error>;
|
|
{{- else if .HasOutput}}
|
|
fn {{rustMethodName .Name}}(&self) -> Result<{{rustOutputType .Output.Type}}, Error>;
|
|
{{- else}}
|
|
fn {{rustMethodName .Name}}(&self) -> Result<(), Error>;
|
|
{{- end}}
|
|
}
|
|
|
|
/// Register the {{rustMethodName .Name}} export.
|
|
/// This macro generates the WASM export function for this method.
|
|
#[macro_export]
|
|
macro_rules! {{registerMacroName .Name}} {
|
|
($plugin_type:ty) => {
|
|
#[extism_pdk::plugin_fn]
|
|
pub fn {{.ExportName}}(
|
|
{{- if .HasInput}}
|
|
req: extism_pdk::Json<$crate::{{snakeCase $.Package}}::{{rustOutputType .Input.Type}}>
|
|
{{- end}}
|
|
) -> extism_pdk::FnResult<{{if .HasOutput}}extism_pdk::Json<{{if isPrimitiveRust .Output.Type}}{{rustOutputType .Output.Type}}{{else}}$crate::{{snakeCase $.Package}}::{{rustOutputType .Output.Type}}{{end}}>{{else}}(){{end}}> {
|
|
let plugin = <$plugin_type>::default();
|
|
{{- if and .HasInput .HasOutput}}
|
|
let result = $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
|
|
Ok(extism_pdk::Json(result))
|
|
{{- else if .HasInput}}
|
|
$crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin, req.into_inner())?;
|
|
Ok(())
|
|
{{- else if .HasOutput}}
|
|
let result = $crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin)?;
|
|
Ok(extism_pdk::Json(result))
|
|
{{- else}}
|
|
$crate::{{snakeCase $.Package}}::{{providerInterface .}}::{{rustMethodName .Name}}(&plugin)?;
|
|
Ok(())
|
|
{{- end}}
|
|
}
|
|
};
|
|
}
|
|
{{- end}}
|
|
{{- end}}
|