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}