pub struct Object { /* private fields */ }Expand description
An owned, identity-verified object kind and exact uncompressed payload.
Storage framing is validated; tree, commit, and tag payload syntax is not. Pass Self::data
to crate::Tree::parse, crate::Commit::parse, or crate::Tag::parse as appropriate.
A packed payload may be shared with the reader’s delta base cache, and clones share it too, so
borrowing it through Self::data costs no copy. Self::into_data copies it only while
another Object or the cache shares it.
use girt::{InitKind, ObjectFormat, PackLimits, ReadLimits, Repository};
let directory = tempfile::tempdir()?;
let repo = Repository::init(
ObjectFormat::Sha1,
directory.path().join("r.git"),
InitKind::Bare,
)?;
let id = repo.loose_objects().write_blob(b"payload\n")?;
let objects = repo.objects_with(PackLimits::default())?;
let object = objects
.read_with(id, ReadLimits::default())?
.ok_or("missing blob")?;
assert_eq!(object.data(), b"payload\n");
assert_eq!(object.id(), id);Implementations§
Source§impl Object
impl Object
Sourcepub fn object_format(&self) -> ObjectFormat
pub fn object_format(&self) -> ObjectFormat
The storage format in which the identity was verified.
Sourcepub fn kind(&self) -> ObjectKind
pub fn kind(&self) -> ObjectKind
The verified Git object type.
Examples found in repository?
examples/packed_repository.rs (line 29)
21fn main() -> Result<(), Box<dyn std::error::Error>> {
22 let args = Args::parse();
23 let repository = Repository::open(args.path)?;
24 let objects = repository.objects()?;
25 let object = objects.read(args.id)?.ok_or("object absent")?;
26
27 eprintln!(
28 "{} {} ({} bytes)",
29 object.kind().as_str(),
30 object.id(),
31 object.data().len()
32 );
33 io::stdout().write_all(object.data())?;
34 Ok(())
35}More examples
examples/write_pack.rs (line 50)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8 let root = tempfile::tempdir()?;
9 let format = girt::ObjectFormat::Sha256;
10 let payload = b"explicit export\0\xff";
11 let id = ObjectId::for_blob(format, payload);
12
13 let inputs = [PackObject {
14 id,
15 kind: ObjectKind::Blob,
16 data: payload,
17 }];
18
19 let mut pack = BufWriter::new(File::create(root.path().join("export.pack"))?);
20 let mut index = BufWriter::new(File::create(root.path().join("export.idx"))?);
21 let written = write_pack(
22 format,
23 &inputs,
24 &mut pack,
25 &mut index,
26 PackWriteLimits::default(),
27 )?;
28
29 pack.flush()?;
30 index.flush()?;
31 drop((pack, index));
32
33 // Only this example owns the new repository. Prepare both files before opening any readers.
34 // A live repository needs a separate safe publication protocol, not this two-rename sequence.
35 let repo_path = root.path().join("private.git");
36 let repo = Repository::init(format, &repo_path, girt::InitKind::Bare)?;
37
38 let basename = format!("objects/pack/pack-{}", written.checksum);
39 fs::rename(
40 root.path().join("export.pack"),
41 repo_path.join(format!("{basename}.pack")),
42 )?;
43 fs::rename(
44 root.path().join("export.idx"),
45 repo_path.join(format!("{basename}.idx")),
46 )?;
47
48 let objects = repo.objects()?;
49 let restored = objects.read(id)?.ok_or("exported object missing")?;
50 assert_eq!(restored.kind(), ObjectKind::Blob);
51 assert_eq!(restored.data(), payload);
52
53 println!(
54 "Verified {} explicit object in {} pack bytes and {} index bytes",
55 written.objects, written.pack_bytes, written.index_bytes
56 );
57 Ok(())
58}Sourcepub fn data(&self) -> &[u8] ⓘ
pub fn data(&self) -> &[u8] ⓘ
Exact uncompressed payload, without the Git object header.
Examples found in repository?
examples/packed_repository.rs (line 31)
21fn main() -> Result<(), Box<dyn std::error::Error>> {
22 let args = Args::parse();
23 let repository = Repository::open(args.path)?;
24 let objects = repository.objects()?;
25 let object = objects.read(args.id)?.ok_or("object absent")?;
26
27 eprintln!(
28 "{} {} ({} bytes)",
29 object.kind().as_str(),
30 object.id(),
31 object.data().len()
32 );
33 io::stdout().write_all(object.data())?;
34 Ok(())
35}More examples
examples/scheduling/fixture.rs (line 93)
83 pub fn operation(&self, gate: Option<Gate>) {
84 let repo = Repository::open(self.root.path()).unwrap();
85 let objects = repo.objects().unwrap();
86
87 if let Some(gate) = gate {
88 gate.started.send(()).unwrap();
89 gate.release.recv().unwrap();
90 }
91
92 let blob = objects.read(self.blob).unwrap().unwrap();
93 assert_eq!(blob.data().len(), 2 * 1024 * 1024);
94 assert_eq!(objects.walk(&[self.tip]).unwrap().len(), 512);
95 }examples/write_pack.rs (line 51)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8 let root = tempfile::tempdir()?;
9 let format = girt::ObjectFormat::Sha256;
10 let payload = b"explicit export\0\xff";
11 let id = ObjectId::for_blob(format, payload);
12
13 let inputs = [PackObject {
14 id,
15 kind: ObjectKind::Blob,
16 data: payload,
17 }];
18
19 let mut pack = BufWriter::new(File::create(root.path().join("export.pack"))?);
20 let mut index = BufWriter::new(File::create(root.path().join("export.idx"))?);
21 let written = write_pack(
22 format,
23 &inputs,
24 &mut pack,
25 &mut index,
26 PackWriteLimits::default(),
27 )?;
28
29 pack.flush()?;
30 index.flush()?;
31 drop((pack, index));
32
33 // Only this example owns the new repository. Prepare both files before opening any readers.
34 // A live repository needs a separate safe publication protocol, not this two-rename sequence.
35 let repo_path = root.path().join("private.git");
36 let repo = Repository::init(format, &repo_path, girt::InitKind::Bare)?;
37
38 let basename = format!("objects/pack/pack-{}", written.checksum);
39 fs::rename(
40 root.path().join("export.pack"),
41 repo_path.join(format!("{basename}.pack")),
42 )?;
43 fs::rename(
44 root.path().join("export.idx"),
45 repo_path.join(format!("{basename}.idx")),
46 )?;
47
48 let objects = repo.objects()?;
49 let restored = objects.read(id)?.ok_or("exported object missing")?;
50 assert_eq!(restored.kind(), ObjectKind::Blob);
51 assert_eq!(restored.data(), payload);
52
53 println!(
54 "Verified {} explicit object in {} pack bytes and {} index bytes",
55 written.objects, written.pack_bytes, written.index_bytes
56 );
57 Ok(())
58}examples/fetch_local.rs (line 83)
20fn main() -> Result<(), Box<dyn std::error::Error>> {
21 let (_source_root, source) = repository()?;
22 let (_destination_root, destination) = repository()?;
23
24 let objects = source.loose_objects();
25 let blob = objects.write_blob(b"Fetched through native local storage\n")?;
26 let tree = objects.write_tree(&Tree::new(
27 girt::ObjectFormat::Sha1,
28 vec![TreeEntry {
29 mode: EntryMode::Blob,
30 name: b"hello.txt".to_vec(),
31 id: blob,
32 }],
33 )?)?;
34
35 let author = Signature::now(b"Fetch Example", b"fetch@example.com")?;
36 let commit = objects.write_commit(&Commit::new(CommitFields {
37 tree,
38 parents: vec![],
39 author: author.clone(),
40 committer: author,
41 extra_headers: vec![],
42 message: b"Local fetch fixture\n".to_vec(),
43 })?)?;
44
45 let branch = RefName::branch("main")?;
46 source.references()?.update_without_reflog(
47 &branch,
48 Target::Direct(commit),
49 Expected::Absent,
50 )?;
51
52 let cancel = AtomicBool::new(false);
53 let received = receive_local(
54 source.git_dir(),
55 |advertisement| {
56 advertisement
57 .refs
58 .iter()
59 .filter(|reference| {
60 reference.name == branch
61 && reference.kind == girt::fetch::AdvertisementKind::Tip
62 })
63 .map(|reference| reference.id)
64 .collect()
65 },
66 girt::fetch::LocalFetchRequest::new(FetchLimits::default()),
67 TransportControl::new(&cancel)
68 .with_deadline(Some(Instant::now() + Duration::from_secs(30))),
69 girt::fetch::LocalFetchObserver::default(),
70 )?;
71
72 let result = received.install(&destination, girt::PackLimits::default(), &cancel)?;
73
74 // Updating a ref is a separate, conditional operation, explicitly without a reflog.
75 destination.references()?.update_without_reflog(
76 &branch,
77 Target::Direct(commit),
78 Expected::Absent,
79 )?;
80
81 let fetched = destination.objects()?;
82 let restored = fetched.read(blob)?.ok_or("missing fetched blob")?;
83 assert_eq!(restored.data(), b"Fetched through native local storage\n");
84
85 println!(
86 "Fetched {} objects ({} pack bytes); published {commit} without a reflog",
87 result.objects,
88 received.pack_bytes()
89 );
90
91 let known = KnownHistory::new(&fetched, &[commit], FetchLimits::default(), &cancel)?;
92 let repeated = receive_local(
93 source.git_dir(),
94 |_| vec![commit],
95 girt::fetch::LocalFetchRequest::new(FetchLimits::default()).with_known(&known),
96 TransportControl::new(&cancel)
97 .with_deadline(Some(Instant::now() + Duration::from_secs(30))),
98 girt::fetch::LocalFetchObserver::default(),
99 )?;
100
101 // Recheck known dependencies in the destination even when no pack was needed.
102 repeated.install(&destination, girt::PackLimits::default(), &cancel)?;
103 assert_eq!(repeated.pack_bytes(), 0);
104 println!(
105 "Repeated fetch: {} objects, {} pack bytes",
106 repeated.object_count(),
107 repeated.pack_bytes()
108 );
109
110 Ok(())
111}examples/push_local.rs (line 85)
23fn main() -> Result<(), Box<dyn std::error::Error>> {
24 let (_source_root, source) = repository()?;
25 let (_destination_root, destination) = repository()?;
26
27 let loose = source.loose_objects();
28 let blob = loose.write_blob(b"Published by girt through native local storage\n")?;
29 let tree = loose.write_tree(&Tree::new(
30 girt::ObjectFormat::Sha1,
31 vec![TreeEntry {
32 mode: EntryMode::Blob,
33 name: b"hello.txt".to_vec(),
34 id: blob,
35 }],
36 )?)?;
37
38 let author = Signature::now(b"Push Example", b"push@example.com")?;
39 let commit = loose.write_commit(&Commit::new(CommitFields {
40 tree,
41 parents: vec![],
42 author: author.clone(),
43 committer: author.clone(),
44 extra_headers: vec![],
45 message: b"Local push fixture\n".to_vec(),
46 })?)?;
47
48 let tag = loose.write_tag(&Tag::new(TagFields {
49 target: commit,
50 target_kind: ObjectKind::Commit,
51 name: b"v1".to_vec(),
52 tagger: Some(author),
53 extra_headers: vec![],
54 message: b"First publication\n".to_vec(),
55 })?)?;
56
57 let cancel = AtomicBool::new(false);
58 let objects = source.objects()?;
59 let commands = vec![
60 PushCommand::new(RefName::new("refs/heads/main")?, None, commit)
61 .with_force(ForcePolicy::FastForwardOnly),
62 PushCommand::new(RefName::new("refs/tags/v1")?, None, tag)
63 .with_force(ForcePolicy::FastForwardOnly),
64 ];
65 let prepared = PreparedPush::new(&objects, commands, &[], PushLimits::default(), &cancel)?;
66
67 let report = send_local(
68 destination.git_dir(),
69 girt::push::LocalPushRequest::new(&prepared),
70 TransportControl::new(&cancel)
71 .with_deadline(Some(Instant::now() + Duration::from_secs(30))),
72 |_| {},
73 )?;
74
75 // A complete protocol exchange can still contain rejection or partial success.
76 if !report.all_succeeded() {
77 return Err(format!("native local push rejected updates: {report:?}").into());
78 }
79
80 let restored = destination
81 .objects()?
82 .read(blob)?
83 .ok_or("missing pushed blob")?;
84 assert_eq!(
85 restored.data(),
86 b"Published by girt through native local storage\n"
87 );
88
89 println!(
90 "Published branch and annotated tag: {} objects, {} pack bytes",
91 prepared.object_count(),
92 prepared.pack_bytes()
93 );
94
95 let repeated = PreparedPush::new(
96 &objects,
97 vec![
98 PushCommand::new(RefName::new("refs/heads/main")?, Some(commit), commit)
99 .with_force(ForcePolicy::FastForwardOnly),
100 ],
101 &[commit],
102 PushLimits::default(),
103 &cancel,
104 )?;
105
106 let report = send_local(
107 destination.git_dir(),
108 girt::push::LocalPushRequest::new(&repeated),
109 TransportControl::new(&cancel)
110 .with_deadline(Some(Instant::now() + Duration::from_secs(30))),
111 |_| {},
112 )?;
113
114 if !report.all_succeeded() {
115 return Err(format!("repeat rejected: {report:?}").into());
116 }
117 assert_eq!(repeated.object_count(), 0);
118 println!(
119 "Repeated push: {} objects, {} pack bytes",
120 repeated.object_count(),
121 repeated.pack_bytes()
122 );
123
124 Ok(())
125}examples/storage_resources.rs (line 146)
47fn main() -> Result<(), Box<dyn std::error::Error>> {
48 let args = Args::parse();
49 let repository = Repository::open(args.repository)?;
50 let id = args.id;
51
52 let baseline = handles();
53 let failed = repository.objects_with(PackLimits::default().with_max_index_bytes(0));
54 assert!(matches!(
55 failed,
56 Err(girt::ObjectReadError::Limit("pack index bytes"))
57 ));
58 assert_eq!(handles(), baseline);
59
60 if args.mode == Some(Mode::Cancel) {
61 let cancelled = AtomicBool::new(false);
62 let start = Instant::now();
63
64 let result = std::thread::scope(|scope| {
65 scope.spawn(|| {
66 std::thread::sleep(Duration::from_millis(10));
67 cancelled.store(true, std::sync::atomic::Ordering::Relaxed);
68 });
69 repository.objects_controlled(
70 PackLimits::default(),
71 AlternateLimits::default(),
72 &cancelled,
73 )
74 });
75
76 assert!(matches!(result, Err(girt::ObjectReadError::Cancelled)));
77 assert_eq!(handles(), baseline);
78
79 println!(
80 "cancel_us={} handles_before={baseline:?} handles_after={:?}",
81 start.elapsed().as_micros(),
82 handles()
83 );
84 return Ok(());
85 }
86
87 let cancelled = AtomicBool::new(false);
88 let start = Instant::now();
89 let mut objects = repository.objects_controlled(
90 PackLimits::default(),
91 AlternateLimits::default(),
92 &cancelled,
93 )?;
94
95 let opened = start.elapsed();
96 let retained = handles();
97 let clone = objects.clone();
98 let cloned = handles();
99
100 let failed = objects.refresh(
101 PackLimits::default().with_max_index_bytes(0),
102 AlternateLimits::default(),
103 );
104 assert!(matches!(
105 failed,
106 Err(girt::ObjectReadError::Limit("pack index bytes"))
107 ));
108 assert_eq!(handles(), cloned);
109
110 let start = Instant::now();
111 objects.refresh(PackLimits::default(), AlternateLimits::default())?;
112 let refreshed = start.elapsed();
113
114 let generations = handles();
115 assert_eq!(
116 generations,
117 baseline
118 .zip(retained)
119 .map(|(base, open)| base + 2 * (open - base))
120 );
121
122 println!(
123 "refresh_us={} handles_two_generations={generations:?}",
124 refreshed.as_micros()
125 );
126
127 let start = Instant::now();
128 let object = clone
129 .read_controlled(id, ReadLimits::default(), &cancelled)?
130 .ok_or("object missing")?;
131 let read = start.elapsed();
132
133 let start = Instant::now();
134 let second = clone
135 .read_with(id, ReadLimits::default())?
136 .ok_or("object missing")?;
137 let reread = start.elapsed();
138
139 assert_eq!(object, second);
140 println!(
141 "pid={} open_us={} first_read_us={} warm_read_us={} payload_bytes={} handles_before={baseline:?} handles_open={retained:?} handles_clone={cloned:?}",
142 std::process::id(),
143 opened.as_micros(),
144 read.as_micros(),
145 reread.as_micros(),
146 object.data().len()
147 );
148
149 drop(second);
150 drop(object);
151 drop(objects);
152 drop(clone);
153
154 println!("handles_after_drop={:?}", handles());
155 assert_eq!(handles(), baseline);
156
157 // Optional sampling interval is outside measured operations and retains no reader.
158 if args.mode == Some(Mode::Hold) {
159 std::thread::sleep(Duration::from_secs(1));
160 }
161 Ok(())
162}Sourcepub fn into_data(self) -> Vec<u8> ⓘ
pub fn into_data(self) -> Vec<u8> ⓘ
Takes ownership of the payload, copying it if another Object or the cache shares it.
use girt::{InitKind, ObjectFormat, PackLimits, ReadLimits, Repository};
let directory = tempfile::tempdir()?;
let repo = Repository::init(
ObjectFormat::Sha1,
directory.path().join("r.git"),
InitKind::Bare,
)?;
let id = repo.loose_objects().write_blob(b"payload")?;
let objects = repo.objects_with(PackLimits::default())?;
let object = objects
.read_with(id, ReadLimits::default())?
.ok_or("blob absent")?;
let retained = object.clone();
let owned = object.into_data(); // A shared payload may be copied; the other owner stays usable.
assert_eq!(owned, retained.data());Sourcepub fn id(&self) -> ObjectId
pub fn id(&self) -> ObjectId
Hashes the kind, canonical header, and payload.
Examples found in repository?
examples/packed_repository.rs (line 30)
21fn main() -> Result<(), Box<dyn std::error::Error>> {
22 let args = Args::parse();
23 let repository = Repository::open(args.path)?;
24 let objects = repository.objects()?;
25 let object = objects.read(args.id)?.ok_or("object absent")?;
26
27 eprintln!(
28 "{} {} ({} bytes)",
29 object.kind().as_str(),
30 object.id(),
31 object.data().len()
32 );
33 io::stdout().write_all(object.data())?;
34 Ok(())
35}Trait Implementations§
impl Eq for Object
impl StructuralPartialEq for Object
Auto Trait Implementations§
impl Freeze for Object
impl RefUnwindSafe for Object
impl Send for Object
impl Sync for Object
impl Unpin for Object
impl UnsafeUnpin for Object
impl UnwindSafe for Object
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more