Skip to content

Commit 5742054

Browse files
committed
substores can have multiple parents
1 parent 4984661 commit 5742054

File tree

5 files changed

+72
-37
lines changed

5 files changed

+72
-37
lines changed

src/annotationstore.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ impl Serialize for AnnotationStore {
685685
if self.substores.len() == 1 {
686686
if let Some(substore) =
687687
<AnnotationStore as StoreFor<AnnotationSubStore>>::iter(self)
688-
.filter(|substore| substore.parent.is_none())
688+
.filter(|substore| substore.parents.contains(&None))
689689
.next()
690690
{
691691
state.serialize_field(
@@ -698,7 +698,7 @@ impl Serialize for AnnotationStore {
698698
} else {
699699
let substores_filenames: Vec<_> =
700700
<AnnotationStore as StoreFor<AnnotationSubStore>>::iter(self)
701-
.filter(|substore| substore.parent.is_none())
701+
.filter(|substore| substore.parents.contains(&None))
702702
.filter_map(|substore| substore.filename())
703703
.collect();
704704
state.serialize_field("@include", &substores_filenames)?;
@@ -1005,6 +1005,7 @@ impl AnnotationStore {
10051005
/// Returns a [`Config`] instance suitable for instantiation of dependent instances like TextResource,AnnotationDataSet and
10061006
/// This will have the working directory set to the annotation store's directory
10071007
pub fn new_config(&self) -> Config {
1008+
debug(&self.config(), || format!("AnnotationStore::new_config"));
10081009
let mut config = self.config().clone();
10091010
config.workdir = self.dirname();
10101011
config

src/api/annotationstore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ impl AnnotationStore {
191191
&'a self,
192192
) -> ResultIter<impl Iterator<Item = ResultItem<'a, AnnotationSubStore>>> {
193193
ResultIter::new_sorted(self.iter().filter_map(|a: &'a AnnotationSubStore| {
194-
if a.parent.is_none() {
194+
if a.parents.contains(&None) {
195195
Some(a.as_resultitem(self, self))
196196
} else {
197197
None

src/api/substore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<'store> ResultItem<'store, AnnotationSubStore> {
8787
let handle = self.handle();
8888
let store = self.store();
8989
ResultIter::new_sorted(store.iter().filter_map(move |a: &'a AnnotationSubStore| {
90-
if a.parent == Some(handle) {
90+
if a.parents.contains(&Some(handle)) {
9191
Some(a.as_resultitem(store, store))
9292
} else {
9393
None

src/resources.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ pub(crate) struct DeserializeTextResource {
11471147
config: Config,
11481148
}
11491149

1150-
impl<'a> DeserializeTextResource {
1150+
impl DeserializeTextResource {
11511151
pub fn new(config: Config) -> Self {
11521152
Self { config }
11531153
}

src/substore.rs

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@ pub struct AnnotationSubStore {
4949
pub(crate) filename: Option<PathBuf>,
5050

5151
#[n(3)]
52-
/// Refers to an index in substores which is the parent of the curent substore. This allows for deeper nesting, it is set to None if this is a first level substore
53-
pub(crate) parent: Option<AnnotationSubStoreHandle>,
52+
/// Refers to indices in substores, indicating which are the parents of the curent substore.
53+
/// A value of `None` means the root store is the parent.
54+
/// This allows for deeper nesting, it is set to None if this is a first level substore
55+
pub(crate) parents: Vec<Option<AnnotationSubStoreHandle>>,
5456

5557
#[n(4)]
5658
pub(crate) annotations: Vec<AnnotationHandle>,
@@ -91,13 +93,26 @@ impl AnnotationSubStore {
9193
self.annotationsets.len()
9294
}
9395

94-
pub fn parent(&self) -> Option<AnnotationSubStoreHandle> {
95-
self.parent
96+
pub fn parents(&self) -> &Vec<Option<AnnotationSubStoreHandle>> {
97+
&self.parents
9698
}
9799

98-
/// Sets the parent of this substore
100+
/// Sets the parent of this substore, may be called multiple times to add multiple parents!
101+
/// The value is wrapped in an option, None means the root store is the parent
99102
fn with_parent(mut self, index: Option<AnnotationSubStoreHandle>) -> Self {
100-
self.parent = index;
103+
self.add_parent(index);
104+
self
105+
}
106+
107+
/// Sets the parent of this substore, may be called multiple times to add multiple parents!
108+
/// The value is wrapped in an option, None means the root store is the parent
109+
fn add_parent(&mut self, index: Option<AnnotationSubStoreHandle>) {
110+
self.parents.push(index);
111+
}
112+
113+
/// Sets the parents of this substore
114+
fn with_parents(mut self, parents: Vec<Option<AnnotationSubStoreHandle>>) -> Self {
115+
self.parents = parents;
101116
self
102117
}
103118

@@ -180,22 +195,29 @@ impl AnnotationStore {
180195
// check if the substore is already loaded (it may be referenced from multiple places)
181196
// in that case we don't need to process it again
182197
let foundpath = Some(get_filepath(filename, self.config.workdir())?);
198+
let mut foundsubstore = None;
183199
for substore in <Self as StoreFor<AnnotationSubStore>>::iter(self) {
184200
if substore.filename == foundpath || substore.filename == Some(filename.into()) {
185-
return Ok(substore.handle().expect("substore must have handle"));
201+
foundsubstore = Some(substore.handle().expect("substore must have handle"));
202+
break;
186203
}
187204
}
205+
if let Some(foundsubstore) = foundsubstore {
206+
let parent_handle = self.config.current_substore_path.last().copied();
207+
let substore: &mut AnnotationSubStore = self.get_mut(foundsubstore)?;
208+
substore.add_parent(parent_handle);
209+
return Ok(foundsubstore);
210+
}
188211
}
189-
let new_index = self.substores.len();
190-
let parent_index = if new_index == 0 {
191-
None
192-
} else {
193-
Some(new_index - 1)
194-
};
195-
let handle = self.insert(
196-
AnnotationSubStore::default()
197-
.with_parent(parent_index.map(|x| AnnotationSubStoreHandle::new(x))),
198-
)?; //this data will be modified whilst parsing
212+
213+
let parent_handle = self.config.current_substore_path.last().copied();
214+
let handle = self.insert(AnnotationSubStore::default().with_parent(parent_handle))?; //this data will be modified whilst parsing
215+
debug(self.config(), || {
216+
format!(
217+
"AnnotationStore.add_substore: adding substore filename={:?}, parent={:?}",
218+
filename, parent_handle
219+
)
220+
});
199221
self.push_current_substore(handle);
200222
self.merge_json_file(filename)?;
201223
self.pop_current_substore();
@@ -214,33 +236,45 @@ impl AnnotationStore {
214236
// check if the substore is already loaded (it may be referenced from multiple places)
215237
// in that case we don't need to process it again
216238
let foundpath = Some(get_filepath(filename, self.config.workdir())?);
239+
let mut foundsubstore = None;
217240
for substore in <Self as StoreFor<AnnotationSubStore>>::iter(self) {
218241
if substore.filename == foundpath || substore.filename == Some(filename.into()) {
219-
return Ok(substore.handle().expect("substore must have handle"));
242+
foundsubstore = Some(substore.handle().expect("substore must have handle"));
243+
break;
220244
}
221245
}
246+
if let Some(foundsubstore) = foundsubstore {
247+
let parent_handle = self.config.current_substore_path.last().copied();
248+
let substore: &mut AnnotationSubStore = self.get_mut(foundsubstore)?;
249+
substore.add_parent(parent_handle);
250+
return Ok(foundsubstore);
251+
}
222252
}
223-
let new_index = self.substores.len();
224-
let parent_index = if new_index == 0 {
225-
None
226-
} else {
227-
Some(new_index - 1)
228-
};
253+
254+
let parent_handle = self.config.current_substore_path.last().copied();
229255
let handle = self.insert(
230256
AnnotationSubStore::default()
231-
.with_filename(filename)
232257
.with_id(id)
233-
.with_parent(parent_index.map(|x| AnnotationSubStoreHandle::new(x))),
258+
.with_filename(filename)
259+
.with_parent(parent_handle),
234260
)?; //this data will be modified whilst parsing
261+
debug(self.config(), || {
262+
format!(
263+
"AnnotationStore.add_substore: adding substore filename={:?}, parent={:?}",
264+
filename, parent_handle
265+
)
266+
});
235267
Ok(handle)
236268
}
237269

238270
/// used to add a substore to the path, indicating which substore is currently being parsed
271+
/// influences the behaviour of add_substore()
239272
fn push_current_substore(&mut self, index: AnnotationSubStoreHandle) {
240273
self.config.current_substore_path.push(index);
241274
}
242275

243276
/// used to add a substore to the path, indicating which substore is currently being parsed
277+
/// influences the behaviour of add_substore()
244278
fn pop_current_substore(&mut self) -> bool {
245279
self.config.current_substore_path.pop().is_some()
246280
}
@@ -380,12 +414,12 @@ impl<'store> Serialize for ResultItem<'store, AnnotationSubStore> {
380414
state.serialize_field("@id", id)?;
381415
}
382416
let substores: Vec<_> = self.substores().collect();
383-
let substore_handle = Some(self.handle());
417+
let substore_handle = self.handle();
384418
if !substores.is_empty() {
385419
if substores.len() == 1 {
386420
if let Some(substore) =
387421
<AnnotationStore as StoreFor<AnnotationSubStore>>::iter(self.store())
388-
.filter(|substore| substore.parent == substore_handle)
422+
.filter(|substore| substore.parents.contains(&Some(substore_handle)))
389423
.next()
390424
{
391425
state.serialize_field(
@@ -398,20 +432,20 @@ impl<'store> Serialize for ResultItem<'store, AnnotationSubStore> {
398432
} else {
399433
let substores_filenames: Vec<_> =
400434
<AnnotationStore as StoreFor<AnnotationSubStore>>::iter(self.store())
401-
.filter(|substore| substore.parent == substore_handle)
435+
.filter(|substore| substore.parents.contains(&Some(substore_handle)))
402436
.filter_map(|substore| substore.filename())
403437
.collect();
404438
state.serialize_field("@include", &substores_filenames)?;
405439
}
406440
}
407441
let wrappedstore: WrappedStore<TextResource, AnnotationStore> =
408-
self.store().wrap_store(substore_handle);
442+
self.store().wrap_store(Some(substore_handle));
409443
state.serialize_field("resources", &wrappedstore)?;
410444
let wrappedstore: WrappedStore<AnnotationDataSet, AnnotationStore> =
411-
self.store().wrap_store(substore_handle);
445+
self.store().wrap_store(Some(substore_handle));
412446
state.serialize_field("annotationsets", &wrappedstore)?;
413447
let wrappedstore: WrappedStore<Annotation, AnnotationStore> =
414-
self.store().wrap_store(substore_handle);
448+
self.store().wrap_store(Some(substore_handle));
415449
state.serialize_field("annotations", &wrappedstore)?;
416450
state.end()
417451
}

0 commit comments

Comments
 (0)