Skip to content

Commit 8d933cb

Browse files
committed
refactor; more comments
related to #31
1 parent 157fa2a commit 8d933cb

File tree

9 files changed

+286
-276
lines changed

9 files changed

+286
-276
lines changed

git-config/src/borrowed.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use crate::{file::File, owned};
2+
3+
pub struct Entry<'a> {
4+
pub(crate) parent: &'a File,
5+
pub(crate) index: usize,
6+
}
7+
8+
impl<'a> Entry<'a> {
9+
pub fn to_editable(&self) -> owned::Entry {
10+
let entry = self.parent.token(self.index).as_entry().expect("entry");
11+
owned::Entry {
12+
name: self.parent.bytes_at(entry.name).into(),
13+
value: entry.value.map(|span| self.parent.bytes_at(span).into()),
14+
span: Some(entry.name),
15+
}
16+
}
17+
}
18+
19+
pub struct Section<'a> {
20+
pub(crate) parent: &'a File,
21+
pub(crate) index: usize,
22+
}
23+
24+
impl<'a> Section<'a> {
25+
pub fn to_editable(&self) -> owned::Section {
26+
let section = self.parent.token(self.index).as_section().expect("section");
27+
owned::Section {
28+
name: self.parent.bytes_at(section.name).into(),
29+
sub_name: section.sub_name.map(|span| self.parent.bytes_at(span).into()),
30+
span: Some(section.name),
31+
entries: self.entries().map(|e| e.to_editable()).collect(),
32+
}
33+
}
34+
}

git-config/src/decode.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::{borrowed, value};
2+
use bstr::BStr;
3+
use quick_error::quick_error;
4+
use std::{borrow::Cow, path::PathBuf};
5+
6+
quick_error! {
7+
#[derive(Debug)]
8+
pub enum Error {
9+
Tbd {
10+
display("let's see what can go wrong and how we do it")
11+
}
12+
NoValue {
13+
display("Entry has no value (TODO: much more error information)")
14+
}
15+
}
16+
}
17+
18+
/// Decode an entry value - it can be [encoded as described in the git config documentation](https://github.com/git/git/blob/e67fbf927dfdf13d0b21dc6ea15dc3c7ef448ea0/Documentation/config.txt#L74:L80)
19+
pub fn value(_input: &BStr) -> Result<Cow<'_, BStr>, Error> {
20+
unimplemented!("decode value from bstr")
21+
}
22+
23+
/// Conversion methods for the value of an entry
24+
impl<'a> borrowed::Entry<'a> {
25+
pub fn as_string(&self) -> Result<Cow<'a, BStr>, Error> {
26+
value(
27+
self.parent.bytes_at(
28+
self.parent
29+
.token(self.index)
30+
.as_entry()
31+
.expect("entry")
32+
.value
33+
.ok_or(Error::NoValue)?,
34+
),
35+
)
36+
.map_err(Into::into)
37+
}
38+
pub fn as_int(&self) -> Result<i64, Error> {
39+
unimplemented!("as int")
40+
}
41+
pub fn as_bool(&self) -> Result<bool, Error> {
42+
unimplemented!("as bool")
43+
}
44+
pub fn as_path(&self) -> Result<PathBuf, Error> {
45+
unimplemented!("as bool")
46+
}
47+
pub fn as_color(&self) -> Result<value::Color, Error> {
48+
unimplemented!("as bool")
49+
}
50+
}

git-config/src/file/edit.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use crate::{borrowed, file::File, owned, Span};
2+
use std::io;
3+
4+
/// Represents a possible edit to the git configuration file
5+
enum Edit {
6+
Delete(Span), // section or entry
7+
SetSection(owned::Section),
8+
SetEntry(owned::Entry),
9+
}
10+
11+
impl Into<Edit> for owned::Section {
12+
fn into(self) -> Edit {
13+
Edit::SetSection(self)
14+
}
15+
}
16+
17+
impl Into<Edit> for owned::Entry {
18+
fn into(self) -> Edit {
19+
Edit::SetEntry(self)
20+
}
21+
}
22+
23+
/// Collects edits to be applied to a [`File`], to be written out eventually.
24+
pub struct Edits<'a> {
25+
parent: &'a File,
26+
edits: Vec<Edit>,
27+
}
28+
29+
impl<'a> Edits<'a> {
30+
pub fn delete_section(&mut self, section: &borrowed::Section<'_>) -> &mut Self {
31+
self.edits.push(Edit::Delete(
32+
self.parent.token(section.index).as_section().expect("section").name,
33+
));
34+
self
35+
}
36+
pub fn delete_entry(&mut self, entry: &borrowed::Entry<'_>) -> &mut Self {
37+
self.edits.push(Edit::Delete(
38+
self.parent.token(entry.index).as_entry().expect("entry").name,
39+
));
40+
self
41+
}
42+
// Use with [`owned::Section`].
43+
//
44+
// Newly [instantiated][owned::Section::new()] sections will be appended, and existing ones can be edited
45+
// by calling [`borrowed::Section::to_editable()`].
46+
pub fn create_or_update_section(&mut self, section: owned::Section) -> &mut Self {
47+
self.edits.push(Edit::SetSection(section));
48+
self
49+
}
50+
pub fn create_or_update_entry(&mut self, entry: owned::Entry) -> &mut Self {
51+
self.edits.push(Edit::SetEntry(entry));
52+
self
53+
}
54+
55+
pub fn to_write(&self, _out: impl io::Write) -> io::Result<()> {
56+
unimplemented!("to write")
57+
}
58+
}
59+
60+
impl File {
61+
pub fn edit(&self) -> Edits {
62+
Edits {
63+
parent: self,
64+
edits: Vec::new(),
65+
}
66+
}
67+
}
Lines changed: 13 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{borrowed, spanned, Span};
22
use bstr::{BStr, ByteSlice};
33

4+
#[derive(Clone, PartialOrd, PartialEq, Ord, Eq)]
45
pub(crate) enum Token {
56
Section(spanned::Section),
67
Entry(spanned::Entry),
@@ -23,13 +24,18 @@ impl Token {
2324
}
2425

2526
/// The entry point into reading and writing git config files.
27+
///
28+
/// After reading a configuration file its contents is stored verbatim and indexed to allow retrieval
29+
/// of sections and entry values on demand. These are returned as [`borrowed`] items, which are read-only but
30+
/// can be transformed into editable items.
31+
#[derive(Clone, PartialOrd, PartialEq, Ord, Eq)]
2632
pub struct File {
2733
buf: Vec<u8>,
2834
/// A config file as parsed into tokens, where each [`Token`] is one of the three relevant items in git config files.
2935
tokens: Vec<Token>, // but how do we get fast lookups and proper value lookup based on decoded values?
3036
// On the fly is easier, otherwise we have to deal with a lookup cache of sorts and
31-
// many more allocations up front (which might be worth it). Cow<'a, _> would bind to
32-
// our buffer so the cache can't be in this type.
37+
// many more allocations up front (which might be worth it only once we have measurements).
38+
// Cow<'a, _> would bind to our buffer so the cache can't be in this type.
3339
// Probably it could be the 'Config' type which handles multiple files and treats them as one,
3440
// and only if there is any need.
3541
}
@@ -45,6 +51,9 @@ impl File {
4551
}
4652

4753
impl File {
54+
/// Returns an iterator over all sections and sub-sections of the configuration file.
55+
///
56+
/// Note that every entry must be part of a section, that is global entries/key-value pairs are not allowed.
4857
pub fn sections(&self) -> impl Iterator<Item = borrowed::Section<'_>> {
4958
self.tokens
5059
.iter()
@@ -54,6 +63,7 @@ impl File {
5463
}
5564

5665
impl<'a> borrowed::Section<'a> {
66+
/// Returns an iterator over all entries in a section.
5767
pub fn entries(&self) -> impl Iterator<Item = borrowed::Entry<'_>> {
5868
struct Iter<'a> {
5969
inner: Option<&'a [Token]>,
@@ -97,72 +107,5 @@ impl<'a> borrowed::Section<'a> {
97107
}
98108
}
99109

100-
mod edit {
101-
use crate::{borrowed, file::File, owned, Span};
102-
use std::io;
103-
104-
impl Into<Edit> for owned::Section {
105-
fn into(self) -> Edit {
106-
Edit::SetSection(self)
107-
}
108-
}
109-
110-
impl Into<Edit> for owned::Entry {
111-
fn into(self) -> Edit {
112-
Edit::SetEntry(self)
113-
}
114-
}
115-
116-
enum Edit {
117-
Delete(Span), // section or entry
118-
SetSection(owned::Section),
119-
SetEntry(owned::Entry),
120-
}
121-
122-
/// Collects edits to be applied to a [`File`], to be written out eventually.
123-
pub struct Edits<'a> {
124-
parent: &'a File,
125-
edits: Vec<Edit>,
126-
}
127-
128-
impl<'a> Edits<'a> {
129-
pub fn delete_section(&mut self, section: &borrowed::Section<'_>) -> &mut Self {
130-
self.edits.push(Edit::Delete(
131-
self.parent.token(section.index).as_section().expect("section").name,
132-
));
133-
self
134-
}
135-
pub fn delete_entry(&mut self, entry: &borrowed::Entry<'_>) -> &mut Self {
136-
self.edits.push(Edit::Delete(
137-
self.parent.token(entry.index).as_entry().expect("entry").name,
138-
));
139-
self
140-
}
141-
// Use with [`owned::Section`].
142-
//
143-
// Newly [instantiated][owned::Section::new()] sections will be appended, and existing ones can be edited
144-
// by calling [`borrowed::Section::to_editable()`].
145-
pub fn create_or_update_section(&mut self, section: owned::Section) -> &mut Self {
146-
self.edits.push(Edit::SetSection(section));
147-
self
148-
}
149-
pub fn create_or_update_entry(&mut self, entry: owned::Entry) -> &mut Self {
150-
self.edits.push(Edit::SetEntry(entry));
151-
self
152-
}
153-
154-
pub fn to_write(&self, _out: impl io::Write) -> io::Result<()> {
155-
unimplemented!("to write")
156-
}
157-
}
158-
159-
impl File {
160-
pub fn edit(&self) -> Edits {
161-
Edits {
162-
parent: self,
163-
edits: Vec::new(),
164-
}
165-
}
166-
}
167-
}
110+
mod edit;
168111
pub use edit::Edits;

0 commit comments

Comments
 (0)