History

[git-ref] refactor

Sebastian Thiel committed 5 years ago

Commit 5bac5851 parent 30b0d546 files · +192 −199Browse files

Unified · Split

6 files
  1. git-ref/src/lib.rs +1 −21
  2. git-ref/src/safe_name.rs +19 −0
  3. git-ref/src/store/loose.rs +0 −178
  4. git-ref/src/store/loose/backend.rs +38 −0
  5. git-ref/src/store/loose/mod.rs +18 −0
  6. git-ref/src/store/loose/reference.rs +116 −0
git-ref/src/lib.rs+1−21
@@ -10,27 +10,7 @@ pub use store::*; · 9 unmodified lines
10 10
11pub struct SafeName<'a>(&'a BStr);11pub struct SafeName<'a>(&'a BStr);
12 12
13mod safe_name {13mod safe_name;
14 use crate::SafeName;
15 use bstr::{BStr, ByteSlice};
16 use std::convert::TryFrom;
17
18 impl<'a> TryFrom<&'a BStr> for SafeName<'a> {
19 type Error = git_validate::reference::name::Error;
20
21 fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
22 Ok(SafeName(git_validate::refname(v)?))
23 }
24 }
25
26 impl<'a> TryFrom<&'a str> for SafeName<'a> {
27 type Error = git_validate::reference::name::Error;
28
29 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
30 Ok(SafeName(git_validate::refname(v.as_bytes().as_bstr())?))
31 }
32 }
33}
34 14
35/// Denotes the kind of function to produce a `Id`15/// Denotes the kind of function to produce a `Id`
36#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]16#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
git-ref/src/safe_name.rs+19−0
@@ -0,0 +1,19 @@
1use crate::SafeName;
2use bstr::{BStr, ByteSlice};
3use std::convert::TryFrom;
4
5impl<'a> TryFrom<&'a BStr> for SafeName<'a> {
6 type Error = git_validate::reference::name::Error;
7
8 fn try_from(v: &'a BStr) -> Result<Self, Self::Error> {
9 Ok(SafeName(git_validate::refname(v)?))
10 }
11}
12
13impl<'a> TryFrom<&'a str> for SafeName<'a> {
14 type Error = git_validate::reference::name::Error;
15
16 fn try_from(v: &'a str) -> Result<Self, Self::Error> {
17 Ok(SafeName(git_validate::refname(v.as_bytes().as_bstr())?))
18 }
19}
git-ref/src/store/loose.rs+0−178
@@ -1,178 +0,0 @@
1use std::path::PathBuf;
2
3#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
4pub struct Reference<'a> {
5 parent: &'a Store,
6 /// The path relative to the stores base at which this reference is located
7 pub relative_path: PathBuf,
8 state: reference::State,
9}
10
11#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
12pub struct Store {
13 /// The location at which loose references can be found as per conventions of a typical git repository
14 pub base: PathBuf,
15}
16
17mod backend {
18 mod find {
19 use crate::{loose, SafeName};
20 use quick_error::quick_error;
21 use std::convert::TryInto;
22
23 quick_error! {
24 #[derive(Debug)]
25 pub enum Error {
26 Tbd
27 }
28 }
29
30 impl loose::Store {
31 pub fn find_one<'a>(&self, _path: impl TryInto<SafeName<'a>>) -> Result<loose::Reference<'_>, Error> {
32 todo!("find one")
33 }
34 }
35 }
36
37 mod init {
38 use crate::loose;
39 use std::path::PathBuf;
40
41 impl loose::Store {
42 pub fn new(path: impl Into<PathBuf>) -> Self {
43 loose::Store { base: path.into() }
44 }
45 }
46
47 impl<P> From<P> for loose::Store
48 where
49 P: Into<PathBuf>,
50 {
51 fn from(path: P) -> Self {
52 loose::Store::new(path)
53 }
54 }
55 }
56}
57
58pub mod reference {
59 use crate::{loose::Reference, Kind, Target};
60 use bstr::BString;
61 use git_hash::ObjectId;
62
63 #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
64 #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
65 pub(crate) enum State {
66 Id(ObjectId),
67 Path(BString),
68 }
69
70 impl<'a> Reference<'a> {
71 pub fn kind(&self) -> Kind {
72 match self.state {
73 State::Path(_) => Kind::Symbolic,
74 State::Id(_) => Kind::Peeled,
75 }
76 }
77 pub fn target(&'a self) -> Target<'a> {
78 match self.state {
79 State::Path(ref path) => Target::Symbolic(path.as_ref()),
80 State::Id(ref oid) => Target::Peeled(oid.as_ref()),
81 }
82 }
83 }
84
85 pub mod decode {
86 use crate::loose::{reference::State, Reference, Store};
87 use bstr::BString;
88 use git_hash::ObjectId;
89 use nom::{
90 branch::alt,
91 bytes::complete::take_while,
92 bytes::complete::{tag, take_while_m_n},
93 combinator::{map, opt},
94 sequence::terminated,
95 IResult,
96 };
97 use quick_error::quick_error;
98 use std::convert::TryInto;
99 use std::{convert::TryFrom, path::PathBuf};
100
101 enum MaybeUnsafeState {
102 Id(ObjectId),
103 UnvalidatedPath(BString),
104 }
105
106 quick_error! {
107 #[derive(Debug)]
108 pub enum Error {
109 Parse(content: BString) {
110 display("{:?} could not be parsed", content)
111 }
112 RefnameValidation{err: git_validate::reference::name::Error, path: BString} {
113 display("The path to a symbolic reference is invalid")
114 source(err)
115 }
116 }
117 }
118
119 impl TryFrom<MaybeUnsafeState> for State {
120 type Error = Error;
121
122 fn try_from(v: MaybeUnsafeState) -> Result<Self, Self::Error> {
123 Ok(match v {
124 MaybeUnsafeState::Id(id) => State::Id(id),
125 MaybeUnsafeState::UnvalidatedPath(path) => {
126 State::Path(match git_validate::refname(path.as_ref()) {
127 Err(err) => return Err(Error::RefnameValidation { err, path }),
128 Ok(_) => path,
129 })
130 }
131 })
132 }
133 }
134
135 impl<'a> Reference<'a> {
136 pub fn try_from_path(
137 parent: &'a Store,
138 relative_path: impl Into<PathBuf>,
139 path_contents: &[u8],
140 ) -> Result<Self, Error> {
141 Ok(Reference {
142 parent,
143 relative_path: relative_path.into(),
144 state: parse(path_contents)
145 .map_err(|err| err.to_string())
146 .map_err(|_| Error::Parse(path_contents.into()))?
147 .1
148 .try_into()?,
149 })
150 }
151 }
152
153 fn is_hex_digit_lc(b: u8) -> bool {
154 matches!(b, b'0'..=b'9' | b'a'..=b'f')
155 }
156
157 fn hex_sha1(i: &[u8]) -> IResult<&[u8], &[u8]> {
158 take_while_m_n(40usize, 40, is_hex_digit_lc)(i)
159 }
160
161 fn newline(i: &[u8]) -> IResult<&[u8], &[u8]> {
162 alt((tag(b"\r\n"), tag(b"\n")))(i)
163 }
164
165 fn parse(bytes: &[u8]) -> IResult<&[u8], MaybeUnsafeState> {
166 let is_space = |b: u8| b == b' ';
167 if let (path, Some(_ref_prefix)) = opt(terminated(tag("ref: "), take_while(is_space)))(bytes)? {
168 map(terminated(take_while(|b| b != b'\r' && b != b'\n'), newline), |path| {
169 MaybeUnsafeState::UnvalidatedPath(path.into())
170 })(path)
171 } else {
172 map(terminated(hex_sha1, newline), |hex| {
173 MaybeUnsafeState::Id(ObjectId::from_hex(hex).expect("prior validation"))
174 })(bytes)
175 }
176 }
177 }
178}
git-ref/src/store/loose/backend.rs+38−0
@@ -0,0 +1,38 @@
1mod find {
2 use crate::{loose, SafeName};
3 use quick_error::quick_error;
4 use std::convert::TryInto;
5
6 quick_error! {
7 #[derive(Debug)]
8 pub enum Error {
9 Tbd
10 }
11 }
12
13 impl loose::Store {
14 pub fn find_one<'a>(&self, _path: impl TryInto<SafeName<'a>>) -> Result<loose::Reference<'_>, Error> {
15 todo!("find one")
16 }
17 }
18}
19
20mod init {
21 use crate::loose;
22 use std::path::PathBuf;
23
24 impl loose::Store {
25 pub fn new(path: impl Into<PathBuf>) -> Self {
26 loose::Store { base: path.into() }
27 }
28 }
29
30 impl<P> From<P> for loose::Store
31 where
32 P: Into<PathBuf>,
33 {
34 fn from(path: P) -> Self {
35 loose::Store::new(path)
36 }
37 }
38}
git-ref/src/store/loose/mod.rs+18−0
@@ -0,0 +1,18 @@
1use std::path::PathBuf;
2
3#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
4pub struct Reference<'a> {
5 parent: &'a Store,
6 /// The path relative to the stores base at which this reference is located
7 pub relative_path: PathBuf,
8 state: reference::State,
9}
10
11#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
12pub struct Store {
13 /// The location at which loose references can be found as per conventions of a typical git repository
14 pub base: PathBuf,
15}
16
17mod backend;
18pub mod reference;
git-ref/src/store/loose/reference.rs+116−0
@@ -0,0 +1,116 @@
1use crate::{loose::Reference, Kind, Target};
2use bstr::BString;
3use git_hash::ObjectId;
4
5#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash, Clone)]
6#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
7pub(crate) enum State {
8 Id(ObjectId),
9 Path(BString),
10}
11
12impl<'a> Reference<'a> {
13 pub fn kind(&self) -> Kind {
14 match self.state {
15 State::Path(_) => Kind::Symbolic,
16 State::Id(_) => Kind::Peeled,
17 }
18 }
19 pub fn target(&'a self) -> Target<'a> {
20 match self.state {
21 State::Path(ref path) => Target::Symbolic(path.as_ref()),
22 State::Id(ref oid) => Target::Peeled(oid.as_ref()),
23 }
24 }
25}
26
27pub mod decode {
28 use crate::loose::{reference::State, Reference, Store};
29 use bstr::BString;
30 use git_hash::ObjectId;
31 use nom::{
32 branch::alt,
33 bytes::complete::take_while,
34 bytes::complete::{tag, take_while_m_n},
35 combinator::{map, opt},
36 sequence::terminated,
37 IResult,
38 };
39 use quick_error::quick_error;
40 use std::convert::TryInto;
41 use std::{convert::TryFrom, path::PathBuf};
42
43 enum MaybeUnsafeState {
44 Id(ObjectId),
45 UnvalidatedPath(BString),
46 }
47
48 quick_error! {
49 #[derive(Debug)]
50 pub enum Error {
51 Parse(content: BString) {
52 display("{:?} could not be parsed", content)
53 }
54 RefnameValidation{err: git_validate::reference::name::Error, path: BString} {
55 display("The path to a symbolic reference is invalid")
56 source(err)
57 }
58 }
59 }
60
61 impl TryFrom<MaybeUnsafeState> for State {
62 type Error = Error;
63
64 fn try_from(v: MaybeUnsafeState) -> Result<Self, Self::Error> {
65 Ok(match v {
66 MaybeUnsafeState::Id(id) => State::Id(id),
67 MaybeUnsafeState::UnvalidatedPath(path) => State::Path(match git_validate::refname(path.as_ref()) {
68 Err(err) => return Err(Error::RefnameValidation { err, path }),
69 Ok(_) => path,
70 }),
71 })
72 }
73 }
74
75 impl<'a> Reference<'a> {
76 pub fn try_from_path(
77 parent: &'a Store,
78 relative_path: impl Into<PathBuf>,
79 path_contents: &[u8],
80 ) -> Result<Self, Error> {
81 Ok(Reference {
82 parent,
83 relative_path: relative_path.into(),
84 state: parse(path_contents)
85 .map_err(|_| Error::Parse(path_contents.into()))?
86 .1
87 .try_into()?,
88 })
89 }
90 }
91
92 fn is_hex_digit_lc(b: u8) -> bool {
93 matches!(b, b'0'..=b'9' | b'a'..=b'f')
94 }
95
96 fn hex_sha1(i: &[u8]) -> IResult<&[u8], &[u8]> {
97 take_while_m_n(40usize, 40, is_hex_digit_lc)(i)
98 }
99
100 fn newline(i: &[u8]) -> IResult<&[u8], &[u8]> {
101 alt((tag(b"\r\n"), tag(b"\n")))(i)
102 }
103
104 fn parse(bytes: &[u8]) -> IResult<&[u8], MaybeUnsafeState> {
105 let is_space = |b: u8| b == b' ';
106 if let (path, Some(_ref_prefix)) = opt(terminated(tag("ref: "), take_while(is_space)))(bytes)? {
107 map(terminated(take_while(|b| b != b'\r' && b != b'\n'), newline), |path| {
108 MaybeUnsafeState::UnvalidatedPath(path.into())
109 })(path)
110 } else {
111 map(terminated(hex_sha1, newline), |hex| {
112 MaybeUnsafeState::Id(ObjectId::from_hex(hex).expect("prior validation"))
113 })(bytes)
114 }
115 }
116}