1use std::ffi::{CStr, CString};
2use std::marker;
3use std::ops::Range;
4use std::path::Path;
5use std::ptr;
6use std::slice;
7
8use libc::{c_char, c_int, c_uint, c_void, size_t};
9
10use crate::util::{self, path_to_repo_path, Binding};
11use crate::IntoCString;
12use crate::{panic, raw, Error, IndexAddOption, IndexTime, Oid, Repository, Tree};
13
14pub struct Index {
18 raw: *mut raw::git_index,
19}
20
21pub struct IndexEntries<'index> {
23 range: Range<usize>,
24 index: &'index Index,
25}
26
27pub struct IndexConflicts<'index> {
29 conflict_iter: *mut raw::git_index_conflict_iterator,
30 _marker: marker::PhantomData<&'index Index>,
31}
32
33pub struct IndexConflict {
35 pub ancestor: Option<IndexEntry>,
37 pub our: Option<IndexEntry>,
40 pub their: Option<IndexEntry>,
43}
44
45pub type IndexMatchedPath<'a> = dyn FnMut(&Path, &[u8]) -> i32 + 'a;
51
52#[allow(missing_docs)]
57#[derive(Debug)]
58pub struct IndexEntry {
59 pub ctime: IndexTime,
60 pub mtime: IndexTime,
61 pub dev: u32,
62 pub ino: u32,
63 pub mode: u32,
64 pub uid: u32,
65 pub gid: u32,
66 pub file_size: u32,
67 pub id: Oid,
68 pub flags: u16,
69 pub flags_extended: u16,
70
71 pub path: Vec<u8>,
86}
87
88impl Index {
89 pub fn new() -> Result<Index, Error> {
94 crate::init();
95 let mut raw = ptr::null_mut();
96 unsafe {
97 try_call!(raw::git_index_new(&mut raw));
98 Ok(Binding::from_raw(raw))
99 }
100 }
101
102 pub fn open(index_path: &Path) -> Result<Index, Error> {
111 crate::init();
112 let mut raw = ptr::null_mut();
113 let index_path = index_path.into_c_string()?;
115 unsafe {
116 try_call!(raw::git_index_open(&mut raw, index_path));
117 Ok(Binding::from_raw(raw))
118 }
119 }
120
121 pub fn version(&self) -> u32 {
127 unsafe { raw::git_index_version(self.raw) }
128 }
129
130 pub fn set_version(&mut self, version: u32) -> Result<(), Error> {
136 unsafe {
137 try_call!(raw::git_index_set_version(self.raw, version));
138 }
139 Ok(())
140 }
141
142 pub fn add(&mut self, entry: &IndexEntry) -> Result<(), Error> {
148 let path = CString::new(&entry.path[..])?;
149
150 let mut flags = entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
154
155 if entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
156 flags |= entry.path.len() as u16;
157 } else {
158 flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
159 }
160
161 unsafe {
162 let raw = raw::git_index_entry {
163 dev: entry.dev,
164 ino: entry.ino,
165 mode: entry.mode,
166 uid: entry.uid,
167 gid: entry.gid,
168 file_size: entry.file_size,
169 id: *entry.id.raw(),
170 flags,
171 flags_extended: entry.flags_extended,
172 path: path.as_ptr(),
173 mtime: raw::git_index_time {
174 seconds: entry.mtime.seconds(),
175 nanoseconds: entry.mtime.nanoseconds(),
176 },
177 ctime: raw::git_index_time {
178 seconds: entry.ctime.seconds(),
179 nanoseconds: entry.ctime.nanoseconds(),
180 },
181 };
182 try_call!(raw::git_index_add(self.raw, &raw));
183 Ok(())
184 }
185 }
186
187 pub fn add_frombuffer(&mut self, entry: &IndexEntry, data: &[u8]) -> Result<(), Error> {
205 let path = CString::new(&entry.path[..])?;
206
207 let mut flags = entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
211
212 if entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
213 flags |= entry.path.len() as u16;
214 } else {
215 flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
216 }
217
218 unsafe {
219 let raw = raw::git_index_entry {
220 dev: entry.dev,
221 ino: entry.ino,
222 mode: entry.mode,
223 uid: entry.uid,
224 gid: entry.gid,
225 file_size: entry.file_size,
226 id: *entry.id.raw(),
227 flags,
228 flags_extended: entry.flags_extended,
229 path: path.as_ptr(),
230 mtime: raw::git_index_time {
231 seconds: entry.mtime.seconds(),
232 nanoseconds: entry.mtime.nanoseconds(),
233 },
234 ctime: raw::git_index_time {
235 seconds: entry.ctime.seconds(),
236 nanoseconds: entry.ctime.nanoseconds(),
237 },
238 };
239
240 let ptr = data.as_ptr() as *const c_void;
241 let len = data.len() as size_t;
242 try_call!(raw::git_index_add_frombuffer(self.raw, &raw, ptr, len));
243 Ok(())
244 }
245 }
246
247 pub fn add_path(&mut self, path: &Path) -> Result<(), Error> {
261 let posix_path = path_to_repo_path(path)?;
262 unsafe {
263 try_call!(raw::git_index_add_bypath(self.raw, posix_path));
264 Ok(())
265 }
266 }
267
268 pub fn add_all<T, I>(
315 &mut self,
316 pathspecs: I,
317 flag: IndexAddOption,
318 mut cb: Option<&mut IndexMatchedPath<'_>>,
319 ) -> Result<(), Error>
320 where
321 T: IntoCString,
322 I: IntoIterator<Item = T>,
323 {
324 let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
325 let ptr = cb.as_mut();
326 let callback = ptr
327 .as_ref()
328 .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
329 unsafe {
330 try_call!(raw::git_index_add_all(
331 self.raw,
332 &raw_strarray,
333 flag.bits() as c_uint,
334 callback,
335 ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
336 ));
337 }
338 Ok(())
339 }
340
341 pub fn clear(&mut self) -> Result<(), Error> {
346 unsafe {
347 try_call!(raw::git_index_clear(self.raw));
348 }
349 Ok(())
350 }
351
352 pub fn len(&self) -> usize {
354 unsafe { raw::git_index_entrycount(&*self.raw) as usize }
355 }
356
357 pub fn is_empty(&self) -> bool {
359 self.len() == 0
360 }
361
362 pub fn get(&self, n: usize) -> Option<IndexEntry> {
364 unsafe {
365 let ptr = raw::git_index_get_byindex(self.raw, n as size_t);
366 if ptr.is_null() {
367 None
368 } else {
369 Some(Binding::from_raw(*ptr))
370 }
371 }
372 }
373
374 pub fn iter(&self) -> IndexEntries<'_> {
376 IndexEntries {
377 range: 0..self.len(),
378 index: self,
379 }
380 }
381
382 pub fn conflicts(&self) -> Result<IndexConflicts<'_>, Error> {
384 crate::init();
385 let mut conflict_iter = ptr::null_mut();
386 unsafe {
387 try_call!(raw::git_index_conflict_iterator_new(
388 &mut conflict_iter,
389 self.raw
390 ));
391 Ok(Binding::from_raw(conflict_iter))
392 }
393 }
394
395 pub fn get_path(&self, path: &Path, stage: i32) -> Option<IndexEntry> {
397 let path = path_to_repo_path(path).unwrap();
398 unsafe {
399 let ptr = call!(raw::git_index_get_bypath(self.raw, path, stage as c_int));
400 if ptr.is_null() {
401 None
402 } else {
403 Some(Binding::from_raw(*ptr))
404 }
405 }
406 }
407
408 pub fn has_conflicts(&self) -> bool {
412 unsafe { raw::git_index_has_conflicts(self.raw) == 1 }
413 }
414
415 pub fn conflict_get(&self, path: &Path) -> Result<IndexConflict, Error> {
417 let path = path_to_repo_path(path)?;
418 let mut ancestor = ptr::null();
419 let mut our = ptr::null();
420 let mut their = ptr::null();
421
422 unsafe {
423 try_call!(raw::git_index_conflict_get(
424 &mut ancestor,
425 &mut our,
426 &mut their,
427 self.raw,
428 path
429 ));
430
431 Ok(IndexConflict {
432 ancestor: match ancestor.is_null() {
433 false => Some(IndexEntry::from_raw(*ancestor)),
434 true => None,
435 },
436 our: match our.is_null() {
437 false => Some(IndexEntry::from_raw(*our)),
438 true => None,
439 },
440 their: match their.is_null() {
441 false => Some(IndexEntry::from_raw(*their)),
442 true => None,
443 },
444 })
445 }
446 }
447
448 pub fn path(&self) -> Option<&Path> {
452 unsafe { crate::opt_bytes(self, raw::git_index_path(&*self.raw)).map(util::bytes2path) }
453 }
454
455 pub fn read(&mut self, force: bool) -> Result<(), Error> {
467 unsafe {
468 try_call!(raw::git_index_read(self.raw, force));
469 }
470 Ok(())
471 }
472
473 pub fn read_tree(&mut self, tree: &Tree<'_>) -> Result<(), Error> {
477 unsafe {
478 try_call!(raw::git_index_read_tree(self.raw, &*tree.raw()));
479 }
480 Ok(())
481 }
482
483 pub fn remove(&mut self, path: &Path, stage: i32) -> Result<(), Error> {
485 let path = path_to_repo_path(path)?;
486 unsafe {
487 try_call!(raw::git_index_remove(self.raw, path, stage as c_int));
488 }
489 Ok(())
490 }
491
492 pub fn remove_path(&mut self, path: &Path) -> Result<(), Error> {
501 let path = path_to_repo_path(path)?;
502 unsafe {
503 try_call!(raw::git_index_remove_bypath(self.raw, path));
504 }
505 Ok(())
506 }
507
508 pub fn remove_dir(&mut self, path: &Path, stage: i32) -> Result<(), Error> {
510 let path = path_to_repo_path(path)?;
511 unsafe {
512 try_call!(raw::git_index_remove_directory(
513 self.raw,
514 path,
515 stage as c_int
516 ));
517 }
518 Ok(())
519 }
520
521 pub fn conflict_remove(&mut self, path: &Path) -> Result<(), Error> {
523 let path = path_to_repo_path(path)?;
524 unsafe {
525 try_call!(raw::git_index_conflict_remove(self.raw, path));
526 }
527 Ok(())
528 }
529
530 pub fn remove_all<T, I>(
536 &mut self,
537 pathspecs: I,
538 mut cb: Option<&mut IndexMatchedPath<'_>>,
539 ) -> Result<(), Error>
540 where
541 T: IntoCString,
542 I: IntoIterator<Item = T>,
543 {
544 let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
545 let ptr = cb.as_mut();
546 let callback = ptr
547 .as_ref()
548 .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
549 unsafe {
550 try_call!(raw::git_index_remove_all(
551 self.raw,
552 &raw_strarray,
553 callback,
554 ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
555 ));
556 }
557 Ok(())
558 }
559
560 pub fn update_all<T, I>(
574 &mut self,
575 pathspecs: I,
576 mut cb: Option<&mut IndexMatchedPath<'_>>,
577 ) -> Result<(), Error>
578 where
579 T: IntoCString,
580 I: IntoIterator<Item = T>,
581 {
582 let (_a, _b, raw_strarray) = crate::util::iter2cstrs_paths(pathspecs)?;
583 let ptr = cb.as_mut();
584 let callback = ptr
585 .as_ref()
586 .map(|_| index_matched_path_cb as extern "C" fn(_, _, _) -> _);
587 unsafe {
588 try_call!(raw::git_index_update_all(
589 self.raw,
590 &raw_strarray,
591 callback,
592 ptr.map(|p| p as *mut _).unwrap_or(ptr::null_mut()) as *mut c_void
593 ));
594 }
595 Ok(())
596 }
597
598 pub fn write(&mut self) -> Result<(), Error> {
601 unsafe {
602 try_call!(raw::git_index_write(self.raw));
603 }
604 Ok(())
605 }
606
607 pub fn write_tree(&mut self) -> Result<Oid, Error> {
619 let mut raw = raw::git_oid {
620 id: [0; raw::GIT_OID_RAWSZ],
621 };
622 unsafe {
623 try_call!(raw::git_index_write_tree(&mut raw, self.raw));
624 Ok(Binding::from_raw(&raw as *const _))
625 }
626 }
627
628 pub fn write_tree_to(&mut self, repo: &Repository) -> Result<Oid, Error> {
633 let mut raw = raw::git_oid {
634 id: [0; raw::GIT_OID_RAWSZ],
635 };
636 unsafe {
637 try_call!(raw::git_index_write_tree_to(&mut raw, self.raw, repo.raw()));
638 Ok(Binding::from_raw(&raw as *const _))
639 }
640 }
641
642 pub fn find_prefix<T: IntoCString>(&self, prefix: T) -> Result<usize, Error> {
646 let mut at_pos: size_t = 0;
647 let entry_path = prefix.into_c_string()?;
648 unsafe {
649 try_call!(raw::git_index_find_prefix(
650 &mut at_pos,
651 self.raw,
652 entry_path
653 ));
654 Ok(at_pos)
655 }
656 }
657}
658
659impl IndexEntry {
660 pub(crate) unsafe fn to_raw(&self) -> Result<(raw::git_index_entry, CString), Error> {
665 let path = CString::new(&self.path[..])?;
666
667 let mut flags = self.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
671
672 if self.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
673 flags |= self.path.len() as u16;
674 } else {
675 flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
676 }
677
678 unsafe {
679 let raw = raw::git_index_entry {
680 dev: self.dev,
681 ino: self.ino,
682 mode: self.mode,
683 uid: self.uid,
684 gid: self.gid,
685 file_size: self.file_size,
686 id: *self.id.raw(),
687 flags,
688 flags_extended: self.flags_extended,
689 path: path.as_ptr(),
690 mtime: raw::git_index_time {
691 seconds: self.mtime.seconds(),
692 nanoseconds: self.mtime.nanoseconds(),
693 },
694 ctime: raw::git_index_time {
695 seconds: self.ctime.seconds(),
696 nanoseconds: self.ctime.nanoseconds(),
697 },
698 };
699
700 Ok((raw, path))
701 }
702 }
703}
704
705impl Binding for Index {
706 type Raw = *mut raw::git_index;
707 unsafe fn from_raw(raw: *mut raw::git_index) -> Index {
708 Index { raw }
709 }
710 fn raw(&self) -> *mut raw::git_index {
711 self.raw
712 }
713}
714
715impl<'index> Binding for IndexConflicts<'index> {
716 type Raw = *mut raw::git_index_conflict_iterator;
717
718 unsafe fn from_raw(raw: *mut raw::git_index_conflict_iterator) -> IndexConflicts<'index> {
719 IndexConflicts {
720 conflict_iter: raw,
721 _marker: marker::PhantomData,
722 }
723 }
724 fn raw(&self) -> *mut raw::git_index_conflict_iterator {
725 self.conflict_iter
726 }
727}
728
729extern "C" fn index_matched_path_cb(
730 path: *const c_char,
731 matched_pathspec: *const c_char,
732 payload: *mut c_void,
733) -> c_int {
734 unsafe {
735 let path = CStr::from_ptr(path).to_bytes();
736 let matched_pathspec = CStr::from_ptr(matched_pathspec).to_bytes();
737
738 panic::wrap(|| {
739 let payload = payload as *mut &mut IndexMatchedPath<'_>;
740 (*payload)(util::bytes2path(path), matched_pathspec) as c_int
741 })
742 .unwrap_or(-1)
743 }
744}
745
746impl Drop for Index {
747 fn drop(&mut self) {
748 unsafe { raw::git_index_free(self.raw) }
749 }
750}
751
752impl<'index> Drop for IndexConflicts<'index> {
753 fn drop(&mut self) {
754 unsafe { raw::git_index_conflict_iterator_free(self.conflict_iter) }
755 }
756}
757
758impl<'index> Iterator for IndexEntries<'index> {
759 type Item = IndexEntry;
760 fn next(&mut self) -> Option<IndexEntry> {
761 self.range.next().map(|i| self.index.get(i).unwrap())
762 }
763}
764
765impl<'index> Iterator for IndexConflicts<'index> {
766 type Item = Result<IndexConflict, Error>;
767 fn next(&mut self) -> Option<Result<IndexConflict, Error>> {
768 let mut ancestor = ptr::null();
769 let mut our = ptr::null();
770 let mut their = ptr::null();
771 unsafe {
772 try_call_iter!(raw::git_index_conflict_next(
773 &mut ancestor,
774 &mut our,
775 &mut their,
776 self.conflict_iter
777 ));
778 Some(Ok(IndexConflict {
779 ancestor: match ancestor.is_null() {
780 false => Some(IndexEntry::from_raw(*ancestor)),
781 true => None,
782 },
783 our: match our.is_null() {
784 false => Some(IndexEntry::from_raw(*our)),
785 true => None,
786 },
787 their: match their.is_null() {
788 false => Some(IndexEntry::from_raw(*their)),
789 true => None,
790 },
791 }))
792 }
793 }
794}
795
796impl Binding for IndexEntry {
797 type Raw = raw::git_index_entry;
798
799 unsafe fn from_raw(raw: raw::git_index_entry) -> IndexEntry {
800 let raw::git_index_entry {
801 ctime,
802 mtime,
803 dev,
804 ino,
805 mode,
806 uid,
807 gid,
808 file_size,
809 id,
810 flags,
811 flags_extended,
812 path,
813 } = raw;
814
815 let mut pathlen = (flags & raw::GIT_INDEX_ENTRY_NAMEMASK) as usize;
819 if pathlen == raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
820 pathlen = CStr::from_ptr(path).to_bytes().len();
821 }
822
823 let path = slice::from_raw_parts(path as *const u8, pathlen);
824
825 IndexEntry {
826 dev,
827 ino,
828 mode,
829 uid,
830 gid,
831 file_size,
832 id: Binding::from_raw(&id as *const _),
833 flags,
834 flags_extended,
835 path: path.to_vec(),
836 mtime: Binding::from_raw(mtime),
837 ctime: Binding::from_raw(ctime),
838 }
839 }
840
841 fn raw(&self) -> raw::git_index_entry {
842 panic!()
844 }
845}
846
847#[cfg(test)]
848mod tests {
849 use std::fs::{self, File};
850 use std::path::Path;
851 use tempfile::TempDir;
852
853 use crate::{ErrorCode, Index, IndexEntry, IndexTime, Oid, Repository, ResetType};
854
855 #[test]
856 fn smoke() {
857 let mut index = Index::new().unwrap();
858 assert!(index.add_path(&Path::new(".")).is_err());
859 index.clear().unwrap();
860 assert_eq!(index.len(), 0);
861 assert!(index.get(0).is_none());
862 assert!(index.path().is_none());
863 assert!(index.read(true).is_err());
864 }
865
866 #[test]
867 fn smoke_from_repo() {
868 let (_td, repo) = crate::test::repo_init();
869 let mut index = repo.index().unwrap();
870 assert_eq!(
871 index.path().map(|s| s.to_path_buf()),
872 Some(repo.path().join("index"))
873 );
874 Index::open(&repo.path().join("index")).unwrap();
875
876 index.clear().unwrap();
877 index.read(true).unwrap();
878 index.write().unwrap();
879 index.write_tree().unwrap();
880 index.write_tree_to(&repo).unwrap();
881 }
882
883 #[test]
884 fn add_all() {
885 let (_td, repo) = crate::test::repo_init();
886 let mut index = repo.index().unwrap();
887
888 let root = repo.path().parent().unwrap();
889 fs::create_dir(&root.join("foo")).unwrap();
890 File::create(&root.join("foo/bar")).unwrap();
891 let mut called = false;
892 index
893 .add_all(
894 ["foo"].iter(),
895 crate::IndexAddOption::DEFAULT,
896 Some(&mut |a: &Path, b: &[u8]| {
897 assert!(!called);
898 called = true;
899 assert_eq!(b, b"foo");
900 assert_eq!(a, Path::new("foo/bar"));
901 0
902 }),
903 )
904 .unwrap();
905 assert!(called);
906
907 called = false;
908 index
909 .remove_all(
910 ["."].iter(),
911 Some(&mut |a: &Path, b: &[u8]| {
912 assert!(!called);
913 called = true;
914 assert_eq!(b, b".");
915 assert_eq!(a, Path::new("foo/bar"));
916 0
917 }),
918 )
919 .unwrap();
920 assert!(called);
921 }
922
923 #[test]
924 fn smoke_add() {
925 let (_td, repo) = crate::test::repo_init();
926 let mut index = repo.index().unwrap();
927
928 let root = repo.path().parent().unwrap();
929 fs::create_dir(&root.join("foo")).unwrap();
930 File::create(&root.join("foo/bar")).unwrap();
931 index.add_path(Path::new("foo/bar")).unwrap();
932 index.write().unwrap();
933 assert_eq!(index.iter().count(), 1);
934
935 let id = index.write_tree().unwrap();
937 let tree = repo.find_tree(id).unwrap();
938 let sig = repo.signature().unwrap();
939 let id = repo.refname_to_id("HEAD").unwrap();
940 let parent = repo.find_commit(id).unwrap();
941 let commit = repo
942 .commit(Some("HEAD"), &sig, &sig, "commit", &tree, &[&parent])
943 .unwrap();
944 let obj = repo.find_object(commit, None).unwrap();
945 repo.reset(&obj, ResetType::Hard, None).unwrap();
946
947 let td2 = TempDir::new().unwrap();
948 let url = crate::test::path2url(&root);
949 let repo = Repository::clone(&url, td2.path()).unwrap();
950 let obj = repo.find_object(commit, None).unwrap();
951 repo.reset(&obj, ResetType::Hard, None).unwrap();
952 }
953
954 #[test]
955 fn add_then_read() {
956 let mut index = Index::new().unwrap();
957 let mut e = entry();
958 e.path = b"foobar".to_vec();
959 index.add(&e).unwrap();
960 let e = index.get(0).unwrap();
961 assert_eq!(e.path.len(), 6);
962 }
963
964 #[test]
965 fn add_then_find() {
966 let mut index = Index::new().unwrap();
967 let mut e = entry();
968 e.path = b"foo/bar".to_vec();
969 index.add(&e).unwrap();
970 let mut e = entry();
971 e.path = b"foo2/bar".to_vec();
972 index.add(&e).unwrap();
973 assert_eq!(index.get(0).unwrap().path, b"foo/bar");
974 assert_eq!(
975 index.get_path(Path::new("foo/bar"), 0).unwrap().path,
976 b"foo/bar"
977 );
978 assert_eq!(index.find_prefix(Path::new("foo2/")), Ok(1));
979 assert_eq!(
980 index.find_prefix(Path::new("empty/")).unwrap_err().code(),
981 ErrorCode::NotFound
982 );
983 }
984
985 #[test]
986 fn add_frombuffer_then_read() {
987 let (_td, repo) = crate::test::repo_init();
988 let mut index = repo.index().unwrap();
989
990 let mut e = entry();
991 e.path = b"foobar".to_vec();
992 let content = b"the contents";
993 index.add_frombuffer(&e, content).unwrap();
994 let e = index.get(0).unwrap();
995 assert_eq!(e.path.len(), 6);
996
997 let b = repo.find_blob(e.id).unwrap();
998 assert_eq!(b.content(), content);
999 }
1000
1001 fn entry() -> IndexEntry {
1002 IndexEntry {
1003 ctime: IndexTime::new(0, 0),
1004 mtime: IndexTime::new(0, 0),
1005 dev: 0,
1006 ino: 0,
1007 mode: 0o100644,
1008 uid: 0,
1009 gid: 0,
1010 file_size: 0,
1011 id: Oid::from_bytes(&[0; 20]).unwrap(),
1012 flags: 0,
1013 flags_extended: 0,
1014 path: Vec::new(),
1015 }
1016 }
1017}