copybook_codec/numeric/alphanumeric.rs
1// SPDX-License-Identifier: AGPL-3.0-or-later
2//! Alphanumeric field encoding helpers.
3//!
4//! This module owns text-to-codepage conversion and fixed-width padding for
5//! COBOL alphanumeric fields.
6
7use crate::options::Codepage;
8use copybook_core::{Error, ErrorCode, Result};
9
10/// Encode an alphanumeric (PIC X) field with right-padding to the declared length.
11///
12/// Converts the UTF-8 input string to the target codepage encoding and then
13/// right-pads with space characters (ASCII `0x20` or EBCDIC `0x40`) to fill
14/// the declared field length.
15///
16/// # Arguments
17/// * `text` - UTF-8 string value to encode
18/// * `field_len` - Declared byte length of the COBOL field
19/// * `codepage` - Target character encoding (ASCII or EBCDIC variant)
20///
21/// # Returns
22/// A vector of exactly `field_len` bytes containing the encoded and padded text.
23///
24/// # Errors
25/// * `CBKE501_JSON_TYPE_MISMATCH` - if the encoded text exceeds `field_len` bytes
26///
27/// # Examples
28///
29/// ```
30/// use copybook_codec::numeric::encode_alphanumeric;
31/// use copybook_codec::Codepage;
32///
33/// // Encode a 5-character string into a 10-byte ASCII field.
34/// let result = encode_alphanumeric("HELLO", 10, Codepage::ASCII).unwrap();
35/// assert_eq!(result.len(), 10);
36/// assert_eq!(&result[..5], b"HELLO");
37/// assert_eq!(&result[5..], b" ");
38/// ```
39///
40/// # See Also
41/// * [`crate::charset::utf8_to_ebcdic`] - Underlying character conversion
42#[inline]
43#[must_use = "Handle the Result or propagate the error"]
44pub fn encode_alphanumeric(text: &str, field_len: usize, codepage: Codepage) -> Result<Vec<u8>> {
45 let encoded_bytes = crate::charset::utf8_to_ebcdic(text, codepage)?;
46
47 if encoded_bytes.len() > field_len {
48 return Err(Error::new(
49 ErrorCode::CBKE501_JSON_TYPE_MISMATCH,
50 format!(
51 "Text length {} exceeds field length {}",
52 encoded_bytes.len(),
53 field_len
54 ),
55 ));
56 }
57
58 let mut result = encoded_bytes;
59 let space_byte = match codepage {
60 Codepage::ASCII => b' ',
61 _ => 0x40,
62 };
63
64 result.resize(field_len, space_byte);
65 Ok(result)
66}