1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//! Transport trait.
//!
//! # Architecture
//! This module defines the low-level contract for sending and receiving raw Git
//! objects over a network. It is distinct from the [`Remote`](crate::traits::core::remote::Remote)
//! module, which handles higher-level repository semantics like refspec negotiation.
//! The `Transport` trait acts as a dumb pipe: it merely maps object hashes to byte streams.
//!
//! # Design Rationale: Streaming I/O
//! The `fetch_object` method returns a `Box<dyn Read>` rather than a `Vec<u8>`.
//! This is a critical architectural decision for network efficiency. Git objects
//! can be massive. By returning a reader, the transport backend can stream data
//! directly from the network socket to the decoder, decompressing on the fly and
//! maintaining a constant memory footprint regardless of the object's size.
use crateVctrlError;
use crateHash;
use Read;
/// Trait for transporting Git objects.
///
/// # Why this exists
/// Provides a backend-agnostic abstraction for the raw transfer of Git objects.
/// Whether the underlying protocol is HTTP, SSH, or the Git wire protocol, this
/// trait allows the core engine to fetch missing objects or push new ones without
/// being coupled to the specific networking implementation or socket management.
///
/// # How it works
/// The trait defines two operations:
/// - `fetch_object`: Downloads an object by its hash, returning a stream.
/// - `push_object`: Uploads an object's data to the remote.
///
/// # Design Rationale: Mutability Split
/// `fetch_object` takes `&self` because it is a read-only operation from the
/// perspective of the transport's state; multiple threads can safely fetch objects
/// concurrently. Conversely, `push_object` takes `&mut self` because writing to
/// a network socket is inherently stateful and often requires sequential, exclusive
/// access to prevent interleaved data corruption.
///
/// # Examples
///
/// Implementing the trait for a mock in-memory transport:
///
/// ```
/// # use std::io::Read;
/// # use libvctrl_handler::traits::core::transport::Transport;
/// # use libvctrl_handler::{Hash, VctrlError};
/// # use std::collections::HashMap;
/// # use std::io::Cursor;
/// #
/// #[derive(Default)]
/// struct MockTransport {
/// remote_store: HashMap<Hash, Vec<u8>>,
/// }
///
/// impl Transport for MockTransport {
/// fn fetch_object(&self, hash: &Hash) -> Result<Box<dyn Read + Send + '_>, VctrlError> {
/// match self.remote_store.get(hash) {
/// Some(data) => Ok(Box::new(Cursor::new(data.clone()))),
/// None => Err(VctrlError::ObjectNotFound(*hash)),
/// }
/// }
///
/// fn push_object(&mut self, hash: &Hash, data: &[u8]) -> Result<(), VctrlError> {
/// self.remote_store.insert(*hash, data.to_vec());
/// Ok(())
/// }
/// }
///
/// let mut transport = MockTransport::default();
/// let hash = Hash::from_bytes(&[0_u8; 64])?;
/// transport.push_object(&hash, b"raw object data")?;
/// assert!(transport.fetch_object(&hash).is_ok());
/// # Ok::<(), VctrlError>(())
/// ```