1#![deny(unsafe_code)]
2use bids_core::error::Result;
10use bids_core::file::BidsFile;
11use bids_io::tsv::read_tsv;
12use bids_layout::BidsLayout;
13use std::collections::HashMap;
14
15pub struct BehLayout<'a> {
16 layout: &'a BidsLayout,
17}
18impl<'a> BehLayout<'a> {
19 pub fn new(layout: &'a BidsLayout) -> Self {
20 Self { layout }
21 }
22 pub fn get_beh_files(&self) -> Result<Vec<BidsFile>> {
23 self.layout.get().datatype("beh").collect()
24 }
25 pub fn get_beh_files_for_subject(&self, s: &str) -> Result<Vec<BidsFile>> {
26 self.layout.get().datatype("beh").subject(s).collect()
27 }
28 pub fn get_beh_files_for_task(&self, t: &str) -> Result<Vec<BidsFile>> {
29 self.layout.get().datatype("beh").task(t).collect()
30 }
31 pub fn get_beh_subjects(&self) -> Result<Vec<String>> {
32 self.layout.get().datatype("beh").return_unique("subject")
33 }
34 pub fn get_beh_tasks(&self) -> Result<Vec<String>> {
35 self.layout.get().datatype("beh").return_unique("task")
36 }
37
38 pub fn get_events(&self, f: &BidsFile) -> Result<Option<Vec<HashMap<String, String>>>> {
39 let p = f.companion("events", "tsv");
40 if p.exists() {
41 Ok(Some(read_tsv(&p)?))
42 } else {
43 Ok(None)
44 }
45 }
46
47 pub fn get_beh_data(&self, f: &BidsFile) -> Result<Option<Vec<HashMap<String, String>>>> {
48 if f.filename.ends_with("_beh.tsv") && f.path.exists() {
49 Ok(Some(read_tsv(&f.path)?))
50 } else {
51 Ok(None)
52 }
53 }
54
55 pub fn summary(&self) -> Result<BehSummary> {
56 let files = self.get_beh_files()?;
57 let subjects = self.get_beh_subjects()?;
58 let tasks = self.get_beh_tasks()?;
59 Ok(BehSummary {
60 n_subjects: subjects.len(),
61 n_files: files.len(),
62 subjects,
63 tasks,
64 })
65 }
66}
67
68#[derive(Debug)]
69pub struct BehSummary {
70 pub n_subjects: usize,
71 pub n_files: usize,
72 pub subjects: Vec<String>,
73 pub tasks: Vec<String>,
74}
75impl std::fmt::Display for BehSummary {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 writeln!(
78 f,
79 "Behavioral Summary: {} subjects, {} files, tasks: {:?}",
80 self.n_subjects, self.n_files, self.tasks
81 )
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use std::io::Write;
89
90 #[test]
91 fn test_beh_events() {
92 let dir = std::env::temp_dir().join("bids_beh_test");
93 std::fs::create_dir_all(&dir).unwrap();
94 let path = dir.join("sub-01_task-test_events.tsv");
95 let mut f = std::fs::File::create(&path).unwrap();
96 writeln!(f, "onset\tduration\ttrial_type").unwrap();
97 writeln!(f, "1.0\t0.5\tgo").unwrap();
98 writeln!(f, "2.0\t0.5\tstop").unwrap();
99
100 let rows = read_tsv(&path).unwrap();
101 assert_eq!(rows.len(), 2);
102 assert_eq!(rows[0]["trial_type"], "go");
103 std::fs::remove_dir_all(&dir).unwrap();
104 }
105}