#![allow(deprecated)]
/*
* server
*
* ## Real-time data The only real-time path to get tracing data is to ingest via OpenTelemetry (`POST /api/public/otel/v1/traces`) and retrieve via Observations API v2 (`GET /api/public/v2/observations`) and Metrics API v2 (`GET /api/public/v2/metrics`). Other public API write and read endpoints can delay data by about 10 minutes. Direct OpenTelemetry exporters must send the `x-langfuse-ingestion-version: 4` header; current Python and JS SDKs already do. See the [Public API docs](https://langfuse.com/docs/api-and-data-platform/features/public-api) and [real-time ingestion](https://langfuse.com/integrations/native/opentelemetry.md#real-time-ingestion). ## Authentication Authenticate with the API using [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication), get API keys in the project settings: - username: Langfuse Public Key - password: Langfuse Secret Key ## Exports - OpenAPI spec: https://cloud.langfuse.com/generated/api/openapi.yml - Self-hosted deployments: interactive API reference at `/api/docs` and OpenAPI spec at `/api/openapi.yaml`
*
* The version of the OpenAPI document:
*
* Generated by: https://openapi-generator.tech
*/
//! Checks a model against the validation keywords of its schema.
//!
//! Every model implements [`Validate`]. Nothing in this crate calls it: validating a request before sending it, or a
//! response after decoding it, is the caller's choice. `validate()` returns every value that breaks a rule, as
//! [`ValidationErrors`], each with the path to it in wire names (`messages[2].content`, `metadata["key"]`): in the
//! order of the fields, nested values depth-first, the entries of a map ordered by their rendered (escaped) key. A
//! valid value allocates nothing.
//!
//! What is checked: `minLength` and `maxLength` (in characters), `pattern`, `minimum`, `maximum`, `exclusiveMinimum`,
//! `exclusiveMaximum`, `multipleOf`, `minItems`, `maxItems`, `uniqueItems` (by equality), `minProperties` and
//! `maxProperties` of maps, in every nested model, list, map and union variant. A `pattern` is matched with the
//! [`regex`](https://docs.rs/regex) crate, whose classes such as `\d` and `\w` are Unicode-aware; a pattern that uses a
//! construct the crate does not support or reads differently from ECMA-262 is not checked (the generator warns).
use std::fmt;
/// A model that can check itself against the validation keywords of its schema.
///
/// The generated models implement it. To implement it by hand, for a type of your own that holds generated models,
/// implement [`validate_into`](Validate::validate_into): push a [`ValidationError`] for each value that breaks a rule,
/// with `path` set to where the value is, and call `validate_into` on the values it holds with their [`Path`]:
///
/// ```ignore
/// use my_client::models::validation::{Path, Rule, Validate, ValidationError};
///
/// struct Order {
/// note: String,
/// items: Vec<my_client::models::Item>,
/// }
///
/// impl Validate for Order {
/// fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
/// let length = self.note.chars().count() as u64;
/// if length > 100 {
/// let mut error = ValidationError::new(Rule::MaxLength(100), format!("length {length}"));
/// error.path = path.field("note").to_string();
/// errors.push(error);
/// }
/// self.items.validate_into(&path.field("items"), errors);
/// }
/// }
/// ```
///
/// `validate()` then returns what `validate_into` pushed, from [`Path::root`].
pub trait Validate {
/// Every value that breaks a validation keyword of the schema; `Ok(())` when none does.
fn validate(&self) -> Result<(), ValidationErrors> {
let mut errors = Vec::new();
self.validate_into(&Path::root(), &mut errors);
if errors.is_empty() {
Ok(())
} else {
Err(ValidationErrors(errors))
}
}
/// Pushes every value that breaks a keyword onto `errors`, with its path below `path`, and nothing when the value
/// is valid. `validate()` calls it with [`Path::root`]; a model calls it on the models it holds with their path.
fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>);
}
/// Every value that breaks a validation keyword, in the order `validate()` found them; never empty.
#[derive(Clone, Debug, PartialEq)]
pub struct ValidationErrors(Vec<ValidationError>);
impl ValidationErrors {
/// How many values break a keyword.
pub fn len(&self) -> usize {
self.0.len()
}
/// Always `false`: `validate()` returns `Ok(())` when nothing breaks a keyword.
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
/// The errors, in order.
pub fn iter(&self) -> std::slice::Iter<'_, ValidationError> {
self.0.iter()
}
/// The errors, as a `Vec`.
pub fn into_vec(self) -> Vec<ValidationError> {
self.0
}
}
impl IntoIterator for ValidationErrors {
type Item = ValidationError;
type IntoIter = std::vec::IntoIter<ValidationError>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a ValidationErrors {
type Item = &'a ValidationError;
type IntoIter = std::slice::Iter<'a, ValidationError>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
/// One line per error.
impl fmt::Display for ValidationErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (index, error) in self.0.iter().enumerate() {
if index > 0 {
f.write_str("\n")?;
}
write!(f, "{error}")?;
}
Ok(())
}
}
impl std::error::Error for ValidationErrors {}
/// Where a value is, in wire names, built on the stack while `validate()` descends: `path.field("items").index(2)`.
/// It is written out (`to_string()`, `messages[2].content`) only for an error.
#[derive(Clone, Copy, Debug)]
pub struct Path<'a> {
parent: Option<&'a Path<'a>>,
segment: Segment<'a>,
}
#[derive(Clone, Copy, Debug)]
enum Segment<'a> {
Root,
Field(&'a str),
Index(usize),
Key(&'a str),
}
impl<'a> Path<'a> {
/// The value `validate()` was called on.
pub fn root() -> Path<'static> {
Path {
parent: None,
segment: Segment::Root,
}
}
/// The value of the field `name`.
pub fn field(&'a self, name: &'a str) -> Path<'a> {
Path {
parent: Some(self),
segment: Segment::Field(name),
}
}
/// The item at `index`.
pub fn index(&'a self, index: usize) -> Path<'a> {
Path {
parent: Some(self),
segment: Segment::Index(index),
}
}
/// The value under `key`.
pub fn key(&'a self, key: &'a str) -> Path<'a> {
Path {
parent: Some(self),
segment: Segment::Key(key),
}
}
fn write(&self, out: &mut String) {
if let Some(parent) = self.parent {
parent.write(out);
}
match self.segment {
Segment::Root => {}
Segment::Field(name) => {
if !out.is_empty() {
out.push('.');
}
out.push_str(name);
}
Segment::Index(index) => out.push_str(&format!("[{index}]")),
Segment::Key(key) => out.push_str(&format!("[{key:?}]")),
}
}
}
impl fmt::Display for Path<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = String::new();
self.write(&mut out);
f.write_str(&out)
}
}
/// Pushes the error of a check, if any, at `path`.
fn push(result: Result<(), ValidationError>, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
if let Err(mut error) = result {
error.path = path.to_string();
errors.push(error);
}
}
/// Sorts the errors a map's entries pushed from `start` on by their rendered (escaped) key, as a map iterates in no
/// fixed order.
#[doc(hidden)]
pub fn sort_by_key(errors: &mut [ValidationError], start: usize, path: &Path<'_>) {
if errors.len() <= start + 1 {
return;
}
let prefix = path.to_string().len();
errors[start..].sort_by(|a, b| key_of(&a.path, prefix).cmp(key_of(&b.path, prefix)));
}
/// The `["key"]` segment that follows the map's own path.
fn key_of(path: &str, prefix: usize) -> &str {
let rest = path.get(prefix..).unwrap_or("");
let mut escaped = false;
for (at, c) in rest.char_indices().skip(2) {
match c {
'\\' if !escaped => escaped = true,
'"' if !escaped => return &rest[..at],
_ => escaped = false,
}
}
rest
}
/// A validation keyword of the schema, with the limit it sets. A number limit is an `f64`, so an integer limit
/// beyond 2^53 shows rounded (the check itself compares integers exactly).
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Rule {
/// `minLength`: the least number of characters.
MinLength(u64),
/// `maxLength`: the greatest number of characters.
MaxLength(u64),
/// `pattern`: a regular expression the string must contain a match of.
Pattern(&'static str),
/// `minimum`
Minimum(f64),
/// `exclusiveMinimum`
ExclusiveMinimum(f64),
/// `maximum`
Maximum(f64),
/// `exclusiveMaximum`
ExclusiveMaximum(f64),
/// `multipleOf`
MultipleOf(f64),
/// `minItems`
MinItems(u64),
/// `maxItems`
MaxItems(u64),
/// `uniqueItems`: no two items are equal.
UniqueItems,
/// `minProperties` of a map.
MinProperties(u64),
/// `maxProperties` of a map.
MaxProperties(u64),
}
impl fmt::Display for Rule {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Rule::MinLength(n) => write!(f, "minLength {n}"),
Rule::MaxLength(n) => write!(f, "maxLength {n}"),
Rule::Pattern(p) => write!(f, "pattern {p:?}"),
Rule::Minimum(n) => write!(f, "minimum {n}"),
Rule::ExclusiveMinimum(n) => write!(f, "exclusiveMinimum {n}"),
Rule::Maximum(n) => write!(f, "maximum {n}"),
Rule::ExclusiveMaximum(n) => write!(f, "exclusiveMaximum {n}"),
Rule::MultipleOf(n) => write!(f, "multipleOf {n}"),
Rule::MinItems(n) => write!(f, "minItems {n}"),
Rule::MaxItems(n) => write!(f, "maxItems {n}"),
Rule::UniqueItems => write!(f, "uniqueItems"),
Rule::MinProperties(n) => write!(f, "minProperties {n}"),
Rule::MaxProperties(n) => write!(f, "maxProperties {n}"),
}
}
}
/// A value that breaks a validation keyword of its schema.
#[derive(Clone, Debug, PartialEq)]
pub struct ValidationError {
/// Where the value is, in wire names: `messages[2].content`, `metadata["key"]`; empty for the value itself.
pub path: String,
/// The keyword it breaks.
pub rule: Rule,
/// What breaks it: the value (a number, or a string for `pattern`), its size (`length 0`, `3 items`,
/// `0 properties`), or the equal items for `uniqueItems`.
pub actual: String,
}
impl ValidationError {
/// An error with an empty path; set `path` to where the value is (`path.to_string()` in `validate_into`).
pub fn new(rule: Rule, actual: impl Into<String>) -> Self {
ValidationError {
path: String::new(),
rule,
actual: actual.into(),
}
}
}
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.path.is_empty() {
write!(f, "{} breaks {}", self.actual, self.rule)
} else {
write!(f, "{}: {} breaks {}", self.path, self.actual, self.rule)
}
}
}
impl std::error::Error for ValidationError {}
impl<T: Validate + ?Sized> Validate for Box<T> {
fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
(**self).validate_into(path, errors);
}
}
impl<T: Validate> Validate for Option<T> {
fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
if let Some(value) = self {
value.validate_into(path, errors);
}
}
}
impl<T: Validate> Validate for Vec<T> {
fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
for (index, item) in self.iter().enumerate() {
item.validate_into(&path.index(index), errors);
}
}
}
impl<T: Validate, S> Validate for std::collections::HashMap<String, T, S> {
fn validate_into(&self, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
let start = errors.len();
for (key, value) in self {
value.validate_into(&path.key(key), errors);
}
sort_by_key(errors, start, path);
}
}
/// A number type a bound can apply to.
pub trait Number: Copy + PartialOrd + fmt::Display {
/// The value as `f64`, to report a limit.
fn as_f64(self) -> f64;
/// Whether the value is a multiple of `factor`; for floating point numbers, within a relative tolerance.
fn is_multiple(self, factor: Self) -> bool;
}
macro_rules! integer {
($($t:ty),*) => {$(
impl Number for $t {
fn as_f64(self) -> f64 {
self as f64
}
fn is_multiple(self, factor: Self) -> bool {
self.checked_rem(factor).is_none_or(|rest| rest == 0)
}
}
)*};
}
integer!(i8, i16, i32, i64, u8, u16, u32, u64);
macro_rules! float {
($($t:ty => $tolerance:expr),*) => {$(
impl Number for $t {
fn as_f64(self) -> f64 {
f64::from(self)
}
fn is_multiple(self, factor: Self) -> bool {
let quotient = self / factor;
(quotient - quotient.round()).abs() <= $tolerance * quotient.abs().max(1.0)
}
}
)*};
}
float!(f32 => 1e-5, f64 => 1e-9);
/// `minLength` and `maxLength`, in characters.
fn check_length(value: &str, min: Option<u64>, max: Option<u64>) -> Result<(), ValidationError> {
let length = value.chars().count() as u64;
if let Some(min) = min.filter(|min| length < *min) {
return Err(ValidationError::new(
Rule::MinLength(min),
format!("length {length}"),
));
}
if let Some(max) = max.filter(|max| length > *max) {
return Err(ValidationError::new(
Rule::MaxLength(max),
format!("length {length}"),
));
}
Ok(())
}
/// `minimum`
fn check_minimum<T: Number>(value: T, bound: T) -> Result<(), ValidationError> {
if value < bound {
return Err(ValidationError::new(
Rule::Minimum(bound.as_f64()),
value.to_string(),
));
}
Ok(())
}
/// `exclusiveMinimum`
fn check_exclusive_minimum<T: Number>(value: T, bound: T) -> Result<(), ValidationError> {
if value <= bound {
return Err(ValidationError::new(
Rule::ExclusiveMinimum(bound.as_f64()),
value.to_string(),
));
}
Ok(())
}
/// `maximum`
fn check_maximum<T: Number>(value: T, bound: T) -> Result<(), ValidationError> {
if value > bound {
return Err(ValidationError::new(
Rule::Maximum(bound.as_f64()),
value.to_string(),
));
}
Ok(())
}
/// `exclusiveMaximum`
fn check_exclusive_maximum<T: Number>(value: T, bound: T) -> Result<(), ValidationError> {
if value >= bound {
return Err(ValidationError::new(
Rule::ExclusiveMaximum(bound.as_f64()),
value.to_string(),
));
}
Ok(())
}
/// `multipleOf`
fn check_multiple_of<T: Number>(value: T, factor: T) -> Result<(), ValidationError> {
if !value.is_multiple(factor) {
return Err(ValidationError::new(
Rule::MultipleOf(factor.as_f64()),
value.to_string(),
));
}
Ok(())
}
/// `minItems` and `maxItems`.
fn check_items(count: usize, min: Option<u64>, max: Option<u64>) -> Result<(), ValidationError> {
let count = count as u64;
if let Some(min) = min.filter(|min| count < *min) {
return Err(ValidationError::new(
Rule::MinItems(min),
format!("{count} items"),
));
}
if let Some(max) = max.filter(|max| count > *max) {
return Err(ValidationError::new(
Rule::MaxItems(max),
format!("{count} items"),
));
}
Ok(())
}
/// `uniqueItems`: no two items are equal.
fn check_unique_items<T: PartialEq>(items: &[T]) -> Result<(), ValidationError> {
for (index, item) in items.iter().enumerate() {
if let Some(first) = items[..index].iter().position(|earlier| earlier == item) {
return Err(ValidationError::new(
Rule::UniqueItems,
format!("items {first} and {index} are equal"),
));
}
}
Ok(())
}
/// `minProperties` and `maxProperties` of a map.
fn check_properties(
count: usize,
min: Option<u64>,
max: Option<u64>,
) -> Result<(), ValidationError> {
let count = count as u64;
if let Some(min) = min.filter(|min| count < *min) {
return Err(ValidationError::new(
Rule::MinProperties(min),
format!("{count} properties"),
));
}
if let Some(max) = max.filter(|max| count > *max) {
return Err(ValidationError::new(
Rule::MaxProperties(max),
format!("{count} properties"),
));
}
Ok(())
}
#[doc(hidden)]
pub fn length(
value: &str,
min: Option<u64>,
max: Option<u64>,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_length(value, min, max), path, errors);
}
#[doc(hidden)]
pub fn minimum<T: Number>(value: T, bound: T, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
push(check_minimum(value, bound), path, errors);
}
#[doc(hidden)]
pub fn exclusive_minimum<T: Number>(
value: T,
bound: T,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_exclusive_minimum(value, bound), path, errors);
}
#[doc(hidden)]
pub fn maximum<T: Number>(value: T, bound: T, path: &Path<'_>, errors: &mut Vec<ValidationError>) {
push(check_maximum(value, bound), path, errors);
}
#[doc(hidden)]
pub fn exclusive_maximum<T: Number>(
value: T,
bound: T,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_exclusive_maximum(value, bound), path, errors);
}
#[doc(hidden)]
pub fn multiple_of<T: Number>(
value: T,
factor: T,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_multiple_of(value, factor), path, errors);
}
#[doc(hidden)]
pub fn items(
count: usize,
min: Option<u64>,
max: Option<u64>,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_items(count, min, max), path, errors);
}
#[doc(hidden)]
pub fn unique_items<T: PartialEq>(items: &[T], path: &Path<'_>, errors: &mut Vec<ValidationError>) {
push(check_unique_items(items), path, errors);
}
#[doc(hidden)]
pub fn properties(
count: usize,
min: Option<u64>,
max: Option<u64>,
path: &Path<'_>,
errors: &mut Vec<ValidationError>,
) {
push(check_properties(count, min, max), path, errors);
}