gity_ipc/
bincode_serde.rs1use bincode::Options;
2use thiserror::Error;
3
4pub const MAX_MESSAGE_SIZE: u64 = 1_048_576;
6
7#[allow(dead_code)]
9pub const MAX_LOG_ENTRY_SIZE: usize = 1_048_576;
10
11pub fn bounded_bincode() -> impl Options {
13 bincode::options()
15}
16
17pub fn validate_message_size(data: &[u8]) -> Result<(), MessageSizeError> {
19 if data.len() > MAX_MESSAGE_SIZE as usize {
20 Err(MessageSizeError::TooLarge {
21 actual: data.len(),
22 max: MAX_MESSAGE_SIZE,
23 })
24 } else {
25 Ok(())
26 }
27}
28
29#[derive(Debug, Error)]
31pub enum MessageSizeError {
32 #[error("message too large: {actual} bytes exceeds maximum of {max} bytes")]
33 TooLarge { actual: usize, max: u64 },
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use crate::{DaemonCommand, JobKind, ValidatedPath};
40
41 #[test]
42 fn small_message_deserializes() {
43 let cmd = DaemonCommand::HealthCheck;
44 let bytes = bounded_bincode().serialize(&cmd).unwrap();
45 assert!(validate_message_size(&bytes).is_ok());
46 }
47
48 #[test]
49 fn oversized_message_rejected() {
50 let data = vec![0u8; 2_000_000]; assert!(matches!(
52 validate_message_size(&data),
53 Err(MessageSizeError::TooLarge {
54 actual: 2_000_000,
55 max: 1_048_576
56 })
57 ));
58 }
59
60 #[test]
61 fn maximum_size_message_allowed() {
62 let data = vec![0u8; 1_048_576]; assert!(validate_message_size(&data).is_ok());
64 }
65
66 #[test]
67 fn bincode_roundtrip_with_limits() {
68 let cmd = DaemonCommand::QueueJob {
69 repo_path: ValidatedPath::new(std::path::PathBuf::from("/test/repo")).unwrap(),
70 job: JobKind::Prefetch,
71 };
72 let bytes = bounded_bincode().serialize(&cmd).unwrap();
74 let decoded: DaemonCommand = bounded_bincode().deserialize(&bytes).unwrap();
75 assert_eq!(cmd, decoded);
76 }
77}