use crate::error::{VBError, VBResult};
use crate::state::file;
use vb6core::error::err_number;
pub fn put_statement(
file_number: i16,
record_number: Option<i64>,
varname: &crate::value::VBVariant,
) -> VBResult<()> {
if !(file::MIN_FILE_NUMBER..=file::MAX_FILE_NUMBER).contains(&file_number) {
return Err(VBError::with_description(
52, format!("Bad file name or number: {}", file_number),
));
}
if !file::is_file_open(file_number) {
return Err(VBError::with_description(
52, format!("File not open: #{}", file_number),
));
}
let file = file::get_file(file_number).ok_or_else(|| {
VBError::with_description(err_number::BAD_FILE_NAME_OR_NUMBER, "File not open")
})?;
let position = if let Some(rec) = record_number {
if rec <= 0 {
return Err(VBError::with_description(
63, "Bad record number",
));
}
rec
} else {
file.position + 1
};
let bytes = match varname {
crate::value::VBVariant::Long(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::Integer(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::Byte(v) => vec![*v],
crate::value::VBVariant::Double(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::Single(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::Currency(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::Boolean(v) => {
if *v {
1i16.to_le_bytes().to_vec()
} else {
0i16.to_le_bytes().to_vec()
}
}
crate::value::VBVariant::Date(v) => v.to_le_bytes().to_vec(),
crate::value::VBVariant::String(s) => {
let mut result = Vec::new();
let len = s.as_str().len() as u16;
result.extend_from_slice(&len.to_le_bytes());
result.extend_from_slice(s.as_str().as_bytes());
result
}
_ => {
return Err(VBError::with_description(
13, "Type mismatch in Put statement",
));
}
};
file::seek_file(file_number, position)?;
file::write_file(file_number, &bytes).map_err(|e| {
VBError::with_description(
57, e.to_string(),
)
})?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::file::{self, AccessMode, LockMode, OpenMode};
use crate::value::VBVariant;
use vb6core::error::err_number;
#[test]
fn put_long_to_binary_file() {
let _guard = crate::state::test_support::lock_test();
let _ = file::close_all_files();
let dir = tempfile::tempdir().unwrap();
file::set_root(dir.path());
let path = std::path::PathBuf::from("test.bin");
file::open_file(
&path,
OpenMode::Binary,
AccessMode::ReadWrite,
LockMode::Shared,
0,
1,
)
.unwrap();
put_statement(1, Some(1), &VBVariant::Long(42)).unwrap();
let result =
crate::library::file::get::get_statement(1, Some(1), VBVariant::Long(0)).unwrap();
assert_eq!(result, VBVariant::Long(42));
let _ = file::close_all_files();
}
#[test]
fn put_string_to_binary_file() {
let _guard = crate::state::test_support::lock_test();
let _ = file::close_all_files();
let dir = tempfile::tempdir().unwrap();
file::set_root(dir.path());
let path = std::path::PathBuf::from("test.bin");
file::open_file(
&path,
OpenMode::Binary,
AccessMode::ReadWrite,
LockMode::Shared,
0,
1,
)
.unwrap();
put_statement(1, Some(1), &VBVariant::from_string("Hello")).unwrap();
let result =
crate::library::file::get::get_statement(1, Some(1), VBVariant::from_string(""))
.unwrap();
assert_eq!(result, VBVariant::from_string("Hello"));
let _ = file::close_all_files();
}
#[test]
fn put_rejects_invalid_file_number() {
let _guard = crate::state::test_support::lock_test();
let result = put_statement(0, Some(1), &VBVariant::Long(42));
assert!(result.is_err());
assert_eq!(
result.unwrap_err().number,
err_number::BAD_FILE_NAME_OR_NUMBER
);
let _ = file::close_all_files();
}
#[test]
fn put_rejects_closed_file() {
let _guard = crate::state::test_support::lock_test();
let _ = file::close_all_files();
let result = put_statement(1, Some(1), &VBVariant::Long(42));
assert!(result.is_err());
assert_eq!(
result.unwrap_err().number,
err_number::BAD_FILE_NAME_OR_NUMBER
);
let _ = file::close_all_files();
}
}