Skip to content

Commit ea0c599

Browse files
committed
remove trait objects
1 parent 19f07e0 commit ea0c599

File tree

11 files changed

+206
-88
lines changed

11 files changed

+206
-88
lines changed

tmc-langs-framework/src/io/submission_processing.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ lazy_static! {
2121

2222
/// Moves some of the contents of source to target based on the given policy.
2323
/// For example, a file source/foo.java would be moved to target/foo.java.
24-
pub fn move_files(
25-
student_file_policy: Box<dyn StudentFilePolicy>,
24+
pub fn move_files<P: StudentFilePolicy>(
25+
student_file_policy: P,
2626
source: &Path,
2727
target: &Path,
2828
) -> Result<()> {
@@ -244,9 +244,7 @@ mod test {
244244
std::fs::create_dir_all(file_path.parent().unwrap()).unwrap();
245245
let _file = std::fs::File::create(&file_path).unwrap();
246246
move_files(
247-
Box::new(EverythingIsStudentFilePolicy::new(
248-
source.path().to_path_buf(),
249-
)),
247+
EverythingIsStudentFilePolicy::new(source.path().to_path_buf()),
250248
source.path(),
251249
target.path(),
252250
)
@@ -275,12 +273,7 @@ mod test {
275273
let file_path = source.path().join(mock_file);
276274
std::fs::create_dir_all(file_path.parent().unwrap()).unwrap();
277275
let _file = std::fs::File::create(&file_path).unwrap();
278-
move_files(
279-
Box::new(NothingIsStudentFilePolicy {}),
280-
source.path(),
281-
target.path(),
282-
)
283-
.unwrap();
276+
move_files(NothingIsStudentFilePolicy {}, source.path(), target.path()).unwrap();
284277

285278
let mut paths = HashSet::new();
286279
for entry in WalkDir::new(target.path()) {

tmc-langs-framework/src/io/zip.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn zip(policy: Box<dyn StudentFilePolicy>, root_directory: &Path) -> Result<
4848
}
4949

5050
/// Finds a project directory in the given zip and unzips it.
51-
pub fn unzip(policy: Box<dyn StudentFilePolicy>, zip: &Path, target: &Path) -> Result<()> {
51+
pub fn unzip<P: StudentFilePolicy>(policy: P, zip: &Path, target: &Path) -> Result<()> {
5252
log::debug!("Unzipping {} to {}", zip.display(), target.display());
5353

5454
let file = File::open(zip).map_err(|e| Error::OpenFile(zip.to_path_buf(), e))?;
@@ -246,7 +246,7 @@ mod test {
246246
init();
247247

248248
assert!(unzip(
249-
Box::new(EverythingIsStudentFilePolicy::new(PathBuf::new())),
249+
EverythingIsStudentFilePolicy::new(PathBuf::new()),
250250
Path::new("nonexistent"),
251251
Path::new(""),
252252
)
@@ -259,9 +259,7 @@ mod test {
259259

260260
let temp = tempdir().unwrap();
261261
unzip(
262-
Box::new(EverythingIsStudentFilePolicy::new(
263-
temp.path().to_path_buf(),
264-
)),
262+
EverythingIsStudentFilePolicy::new(temp.path().to_path_buf()),
265263
Path::new("tests/data/zip/module-trivial.zip"),
266264
temp.path(),
267265
)
@@ -278,9 +276,7 @@ mod test {
278276

279277
let temp = tempdir().unwrap();
280278
unzip(
281-
Box::new(EverythingIsStudentFilePolicy::new(
282-
temp.path().to_path_buf(),
283-
)),
279+
EverythingIsStudentFilePolicy::new(temp.path().to_path_buf()),
284280
Path::new("tests/data/zip/course-module-trivial.zip"),
285281
temp.path(),
286282
)
@@ -297,9 +293,7 @@ mod test {
297293

298294
let temp = tempdir().unwrap();
299295
unzip(
300-
Box::new(EverythingIsStudentFilePolicy::new(
301-
temp.path().to_path_buf(),
302-
)),
296+
EverythingIsStudentFilePolicy::new(temp.path().to_path_buf()),
303297
Path::new("tests/data/zip/no-src-entry.zip"),
304298
temp.path(),
305299
)

tmc-langs-framework/src/plugin.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ use walkdir::WalkDir;
2626
/// Implementations must be thread-safe and preferably fully stateless. Users of
2727
/// this interface are free to cache results if needed.
2828
pub trait LanguagePlugin {
29+
type StudentFilePolicy: StudentFilePolicy + 'static;
30+
2931
/// Returns the name of the plug-in.
30-
fn get_plugin_name(&self) -> &str;
32+
fn get_plugin_name() -> &'static str;
3133

3234
/// Returns a list of all directories inside that contain an exercise in this
3335
/// language.
@@ -43,7 +45,7 @@ pub trait LanguagePlugin {
4345
.filter_entry(|e| e.path().is_dir())
4446
.filter_map(|e| e.ok())
4547
{
46-
if self.is_exercise_type_correct(entry.path()) {
48+
if Self::is_exercise_type_correct(entry.path()) {
4749
debug!("found exercise {}", entry.path().display());
4850
exercises.push(entry.into_path());
4951
}
@@ -63,8 +65,7 @@ pub trait LanguagePlugin {
6365

6466
/// Runs the tests for the exercise.
6567
fn run_tests(&self, path: &Path) -> Result<RunResult> {
66-
let timeout = self
67-
.get_student_file_policy(path)
68+
let timeout = Self::get_student_file_policy(path)
6869
.get_tmc_project_yml()
6970
.ok()
7071
.and_then(|t| t.tests_timeout_ms.map(Duration::from_millis));
@@ -82,7 +83,7 @@ pub trait LanguagePlugin {
8283
/// easily replace the tests.
8384
fn prepare_submission(
8485
&self,
85-
policy: Box<dyn StudentFilePolicy>,
86+
policy: Self::StudentFilePolicy,
8687
submission_path: &Path,
8788
dest_path: &Path,
8889
) -> Result<()> {
@@ -124,24 +125,24 @@ pub trait LanguagePlugin {
124125

125126
/// Compress a given project so that it can be sent to the TestMyCode server.
126127
fn compress_project(&self, path: &Path) -> Result<Vec<u8>> {
127-
let policy = self.get_student_file_policy(path);
128-
Ok(zip::zip(policy, path)?)
128+
let policy = Self::get_student_file_policy(path);
129+
Ok(zip::zip(Box::new(policy), path)?)
129130
}
130131

131-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy>;
132+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy;
132133

133134
/// Extract a given archive file containing a compressed project to a target location.
134135
///
135136
/// This will overwrite any existing files as long as they are not specified as student files
136137
/// by the language dependent student file policy.
137138
fn extract_project(&self, compressed_project: &Path, target_location: &Path) -> Result<()> {
138-
let policy = self.get_student_file_policy(target_location);
139+
let policy = Self::get_student_file_policy(target_location);
139140
zip::unzip(policy, compressed_project, target_location)?;
140141
Ok(())
141142
}
142143

143144
/// Tells if there's a valid exercise in this path.
144-
fn is_exercise_type_correct(&self, path: &Path) -> bool;
145+
fn is_exercise_type_correct(path: &Path) -> bool;
145146

146147
/// Copy shared stuff to stub or solution used for example for copying tmc-junit-runner.
147148
#[allow(unused_variables)]
@@ -206,11 +207,13 @@ mod test {
206207
}
207208

208209
impl LanguagePlugin for MockPlugin {
209-
fn get_student_file_policy(&self, _project_path: &Path) -> Box<dyn StudentFilePolicy> {
210+
type StudentFilePolicy = MockPolicy;
211+
212+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
210213
unimplemented!()
211214
}
212215

213-
fn get_plugin_name(&self) -> &'static str {
216+
fn get_plugin_name() -> &'static str {
214217
unimplemented!()
215218
}
216219

@@ -226,7 +229,7 @@ mod test {
226229
unimplemented!()
227230
}
228231

229-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
232+
fn is_exercise_type_correct(path: &Path) -> bool {
230233
!path.to_str().unwrap().contains("ignored")
231234
}
232235

tmc-langs-java/src/ant.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ impl AntPlugin {
7171
}
7272

7373
impl LanguagePlugin for AntPlugin {
74-
fn get_plugin_name(&self) -> &str {
74+
type StudentFilePolicy = AntStudentFilePolicy;
75+
76+
fn get_plugin_name() -> &'static str {
7577
"apache-ant"
7678
}
7779

@@ -80,7 +82,7 @@ impl LanguagePlugin for AntPlugin {
8082
}
8183

8284
fn scan_exercise(&self, path: &Path, exercise_name: String) -> Result<ExerciseDesc, Error> {
83-
if !self.is_exercise_type_correct(path) {
85+
if !Self::is_exercise_type_correct(path) {
8486
return JavaError::InvalidExercise.into();
8587
}
8688

@@ -96,13 +98,13 @@ impl LanguagePlugin for AntPlugin {
9698
Ok(self.run_java_tests(project_root_path)?)
9799
}
98100

99-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
101+
fn is_exercise_type_correct(path: &Path) -> bool {
100102
path.join(BUILD_FILE_NAME).exists()
101103
|| path.join("test").exists() && path.join("src").exists()
102104
}
103105

104-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy> {
105-
Box::new(AntStudentFilePolicy::new(project_path.to_path_buf()))
106+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
107+
AntStudentFilePolicy::new(project_path.to_path_buf())
106108
}
107109

108110
fn maybe_copy_shared_stuff(&self, dest_path: &Path) -> Result<(), Error> {

tmc-langs-java/src/maven.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ impl MavenPlugin {
7373
}
7474

7575
impl LanguagePlugin for MavenPlugin {
76-
fn get_plugin_name(&self) -> &str {
76+
type StudentFilePolicy = MavenStudentFilePolicy;
77+
78+
fn get_plugin_name() -> &'static str {
7779
"apache-maven"
7880
}
7981

@@ -82,7 +84,7 @@ impl LanguagePlugin for MavenPlugin {
8284
}
8385

8486
fn scan_exercise(&self, path: &Path, exercise_name: String) -> Result<ExerciseDesc, Error> {
85-
if !self.is_exercise_type_correct(path) {
87+
if !Self::is_exercise_type_correct(path) {
8688
return JavaError::InvalidExercise.into();
8789
}
8890

@@ -98,12 +100,12 @@ impl LanguagePlugin for MavenPlugin {
98100
Ok(self.run_java_tests(project_root_path)?)
99101
}
100102

101-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
103+
fn is_exercise_type_correct(path: &Path) -> bool {
102104
path.join("pom.xml").exists()
103105
}
104106

105-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy> {
106-
Box::new(MavenStudentFilePolicy::new(project_path.to_path_buf()))
107+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
108+
MavenStudentFilePolicy::new(project_path.to_path_buf())
107109
}
108110

109111
fn clean(&self, path: &Path) -> Result<(), Error> {

tmc-langs-java/src/plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ pub(crate) trait JavaPlugin: LanguagePlugin {
151151
exercise_name: String,
152152
compile_result: CompileResult,
153153
) -> Result<ExerciseDesc, JavaError> {
154-
if !self.is_exercise_type_correct(path) || !compile_result.status_code.success() {
154+
if !Self::is_exercise_type_correct(path) || !compile_result.status_code.success() {
155155
return Err(JavaError::InvalidExercise);
156156
}
157157

tmc-langs-make/src/plugin.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,14 @@ impl MakePlugin {
117117
}
118118

119119
impl LanguagePlugin for MakePlugin {
120-
fn get_plugin_name(&self) -> &str {
120+
type StudentFilePolicy = MakeStudentFilePolicy;
121+
122+
fn get_plugin_name() -> &'static str {
121123
"make"
122124
}
123125

124126
fn scan_exercise(&self, path: &Path, exercise_name: String) -> Result<ExerciseDesc, Error> {
125-
if !self.is_exercise_type_correct(path) {
127+
if !Self::is_exercise_type_correct(path) {
126128
return MakeError::NoExerciseFound.into();
127129
}
128130

@@ -247,11 +249,11 @@ impl LanguagePlugin for MakePlugin {
247249
Ok(run_result)
248250
}
249251

250-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy> {
251-
Box::new(MakeStudentFilePolicy::new(project_path.to_path_buf()))
252+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
253+
MakeStudentFilePolicy::new(project_path.to_path_buf())
252254
}
253255

254-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
256+
fn is_exercise_type_correct(path: &Path) -> bool {
255257
path.join("Makefile").is_file()
256258
}
257259

tmc-langs-notests/src/lib.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl NoTestsPlugin {
1818
}
1919

2020
fn get_points(&self, path: &Path) -> Vec<String> {
21-
self.get_student_file_policy(path)
21+
Self::get_student_file_policy(path)
2222
.get_tmc_project_yml()
2323
.ok()
2424
.and_then(|c| c.no_tests.map(|n| n.points))
@@ -27,7 +27,9 @@ impl NoTestsPlugin {
2727
}
2828

2929
impl LanguagePlugin for NoTestsPlugin {
30-
fn get_plugin_name(&self) -> &str {
30+
type StudentFilePolicy = EverythingIsStudentFilePolicy;
31+
32+
fn get_plugin_name() -> &'static str {
3133
"No-Tests"
3234
}
3335

@@ -60,14 +62,12 @@ impl LanguagePlugin for NoTestsPlugin {
6062
})
6163
}
6264

63-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy> {
64-
Box::new(EverythingIsStudentFilePolicy::new(
65-
project_path.to_path_buf(),
66-
))
65+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
66+
EverythingIsStudentFilePolicy::new(project_path.to_path_buf())
6767
}
6868

69-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
70-
self.get_student_file_policy(path)
69+
fn is_exercise_type_correct(path: &Path) -> bool {
70+
Self::get_student_file_policy(path)
7171
.get_tmc_project_yml()
7272
.map(|c| c.no_tests.is_some())
7373
.unwrap_or(false)
@@ -92,7 +92,7 @@ mod test {
9292

9393
let plugin = NoTestsPlugin {};
9494
let path = Path::new("tests/data/notests");
95-
assert!(plugin.is_exercise_type_correct(path));
95+
assert!(NoTestsPlugin::is_exercise_type_correct(path));
9696
let desc = plugin
9797
.scan_exercise(path, "No Tests Exercise".to_string())
9898
.unwrap();
@@ -108,7 +108,7 @@ mod test {
108108

109109
let plugin = NoTestsPlugin {};
110110
let path = Path::new("tests/data/notests-points");
111-
assert!(plugin.is_exercise_type_correct(path));
111+
assert!(NoTestsPlugin::is_exercise_type_correct(path));
112112
let desc = plugin
113113
.scan_exercise(path, "No Tests Exercise".to_string())
114114
.unwrap();

tmc-langs-python3/src/plugin.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ impl Python3Plugin {
2727
}
2828

2929
impl LanguagePlugin for Python3Plugin {
30-
fn get_plugin_name(&self) -> &'static str {
30+
type StudentFilePolicy = Python3StudentFilePolicy;
31+
32+
fn get_plugin_name() -> &'static str {
3133
"python3"
3234
}
3335

34-
fn get_student_file_policy(&self, project_path: &Path) -> Box<dyn StudentFilePolicy> {
35-
Box::new(Python3StudentFilePolicy::new(project_path.to_owned()))
36+
fn get_student_file_policy(project_path: &Path) -> Self::StudentFilePolicy {
37+
Python3StudentFilePolicy::new(project_path.to_owned())
3638
}
3739

3840
fn scan_exercise(&self, path: &Path, exercise_name: String) -> Result<ExerciseDesc, Error> {
@@ -60,7 +62,7 @@ impl LanguagePlugin for Python3Plugin {
6062
Ok(parse_test_result(path)?)
6163
}
6264

63-
fn is_exercise_type_correct(&self, path: &Path) -> bool {
65+
fn is_exercise_type_correct(path: &Path) -> bool {
6466
let mut setup = path.to_owned();
6567
setup.push("setup.py");
6668

@@ -292,10 +294,10 @@ mod test {
292294
init();
293295
let plugin = Python3Plugin::new();
294296

295-
let correct = plugin.is_exercise_type_correct(Path::new("tests/data"));
297+
let correct = Python3Plugin::is_exercise_type_correct(Path::new("tests/data"));
296298
assert!(correct);
297299

298-
let correct = plugin.is_exercise_type_correct(Path::new("./"));
300+
let correct = Python3Plugin::is_exercise_type_correct(Path::new("./"));
299301
assert!(!correct);
300302
}
301303

0 commit comments

Comments
 (0)