Skip to main content

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}