Skip to main content

doc_quad/core/
buffer.rs

1// src/core/buffer.rs
2use crate::error::DocQuadError;
3use ndarray::ArrayView2;
4use std::time::Instant;
5
6/// 核心图像缓冲区,支持非连续内存 (Row Stride)。
7///
8/// # 生命周期
9/// `'a` 绑定到原始数据切片,确保编译期内存安全。
10///
11/// # 字段说明
12/// - `data`:原始 Y 通道字节切片引用
13/// - `width`:图像有效像素宽度
14/// - `height`:图像高度
15/// - `stride`:每行实际字节数(含 Padding,stride >= width)
16pub struct DocBuffer<'a> {
17    /// 原始 Y 通道数据引用
18    pub data: &'a [u8],
19    /// 图像宽度(像素)
20    pub width: u32,
21    /// 图像高度(像素)
22    pub height: u32,
23    /// 行步长(字节数,含 Padding)
24    pub stride: u32,
25}
26
27impl<'a> DocBuffer<'a> {
28    /// 创建新的缓冲区实例,执行边界合法性校验。
29    ///
30    /// # 错误
31    /// - `stride < width`:步长小于宽度,布局非法
32    /// - `height * stride > data.len()`:数据长度不足
33    /// - 乘法溢出(32 位平台超大分辨率)
34    pub fn new(data: &'a [u8], width: u32, height: u32, stride: u32) -> Result<Self, DocQuadError> {
35        let start = Instant::now();
36
37        // P1 修复:使用 checked_mul 防止 32 位平台整数溢出
38        let required = (height as usize)
39            .checked_mul(stride as usize)
40            .ok_or(DocQuadError::InvalidBuffer)?;
41
42        if stride < width || required > data.len() {
43            log::error!(
44                "[Core::DocBuffer] - Buffer dimensions mismatch. data_len={}, required={}",
45                data.len(),
46                required
47            );
48            return Err(DocQuadError::InvalidBuffer);
49        }
50
51        let buffer = Self {
52            data,
53            width,
54            height,
55            stride,
56        };
57
58        log::debug!(
59            "[Core::DocBuffer] - Buffer initialized: {}x{}, stride={}. Elapsed: {}µs",
60            width,
61            height,
62            stride,
63            start.elapsed().as_micros()
64        );
65        Ok(buffer)
66    }
67
68    /// 将缓冲区转换为 ndarray 二维视图,支持零拷贝处理 Row Stride。
69    ///
70    /// # 注意
71    /// `from_shape_ptr` 为 unsafe 函数,直接返回 `ArrayView2`(非 Result),
72    /// 因此先通过 `ndarray::Ix2` + `strides` 构造合法 shape,再进入 unsafe 块。
73    /// 若将来扩展至其他像素格式(如 u16 深度图),需将 stride 除以 sizeof(T)。
74    pub fn as_array_view(&self) -> Result<ArrayView2<'_, u8>, DocQuadError> {
75        let rows = self.height as usize;
76        let cols = self.width as usize;
77        let row_stride = self.stride as usize;
78
79        // 构造带 Stride 的 shape(行步长以元素为单位,列步长为 1)
80        let shape = ndarray::Ix2(rows, cols);
81        let strides = ndarray::Ix2(row_stride, 1);
82
83        // SAFETY:
84        // - data 的生命周期由 'a 保证,不会在视图存活期间被释放
85        // - shape 与 strides 已通过 new() 校验:stride >= width,height * stride <= data.len()
86        // - 所有访问偏移 y * row_stride + x < data.len(),不会越界
87        let view = unsafe {
88            ArrayView2::from_shape_ptr(
89                ndarray::ShapeBuilder::strides(shape, strides),
90                self.data.as_ptr(),
91            )
92        };
93
94        log::debug!(
95            "[Core::DocBuffer] - ArrayView2 mapped: {}x{}, row_stride={}",
96            cols,
97            rows,
98            row_stride
99        );
100
101        Ok(view)
102    }
103}