Skip to main content

uqa_analysis/descriptor/
limits.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Descriptor and external-source bounds apply before a compiled handle is published.
8
9use std::io::{self, Write};
10
11use serde::Serialize;
12
13use crate::{AnalysisError, AnalysisResult};
14
15#[derive(Debug, Clone, Copy)]
16pub struct AnalyzerLimits {
17    pub max_descriptor_bytes: usize,
18    pub max_stages: usize,
19    pub max_cached_analyzers: usize,
20    pub max_cached_descriptor_bytes: usize,
21}
22
23impl Default for AnalyzerLimits {
24    fn default() -> Self {
25        Self {
26            max_descriptor_bytes: 16 * 1024 * 1024,
27            max_stages: 256,
28            max_cached_analyzers: 128,
29            max_cached_descriptor_bytes: 8 * 1024 * 1024,
30        }
31    }
32}
33
34pub(crate) fn check_limit(
35    resource: &'static str,
36    required: usize,
37    limit: usize,
38) -> AnalysisResult<()> {
39    if required > limit {
40        return Err(AnalysisError::ResourceLimit {
41            resource,
42            required,
43            limit,
44        });
45    }
46    Ok(())
47}
48
49struct BoundedWriter {
50    bytes: Vec<u8>,
51    length: usize,
52    maximum: usize,
53    retain: bool,
54    exceeded: Option<usize>,
55}
56
57impl Write for BoundedWriter {
58    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
59        let required = self
60            .length
61            .checked_add(bytes.len())
62            .ok_or_else(|| io::Error::other("analyzer size overflow"))?;
63        if required > self.maximum {
64            self.exceeded = Some(required);
65            return Err(io::Error::other("analyzer descriptor exceeds its limit"));
66        }
67        if self.retain {
68            self.bytes.extend_from_slice(bytes);
69        }
70        self.length = required;
71        Ok(bytes.len())
72    }
73    fn flush(&mut self) -> io::Result<()> {
74        Ok(())
75    }
76}
77
78pub(super) fn encode(
79    value: &impl Serialize,
80    maximum: usize,
81    retain: bool,
82) -> AnalysisResult<Vec<u8>> {
83    let mut writer = BoundedWriter {
84        bytes: Vec::new(),
85        length: 0,
86        maximum,
87        retain,
88        exceeded: None,
89    };
90    let result = serde_json::to_writer(&mut writer, value);
91    if let Some(required) = writer.exceeded {
92        return Err(AnalysisError::ResourceLimit {
93            resource: "analyzer descriptor bytes",
94            required,
95            limit: maximum,
96        });
97    }
98    result?;
99    Ok(writer.bytes)
100}