Решение на Форматиране на импорти от Александър Гуров
Към профила на Александър Гуров
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 19 успешни тест(а)
- 1 неуспешни тест(а)
Код
use std::{
collections::{HashSet, VecDeque},
vec,
};
#[derive(Clone, Copy)]
pub struct Import<'a>(pub &'a [&'a str]);
impl<'a> PartialEq for Import<'a> {
fn eq(&self, other: &Self) -> bool {
self.0.iter().fold(String::new(), |acc, x| acc + x)
== other.0.iter().fold(String::new(), |acc, x| acc + x)
}
}
impl<'a> Eq for Import<'a> {}
impl<'a> PartialOrd for Import<'a> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'a> Ord for Import<'a> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0
.iter()
.fold(String::new(), |acc, x| acc + x)
.cmp(&other.0.iter().fold(String::new(), |acc, x| acc + x))
}
}
pub enum Order {
Original,
Sorted,
}
#[derive(Debug)]
enum ImportNodeType {
Import,
ClosingBrace,
}
#[derive(Debug)]
struct ImportNode {
value: String,
children: Vec<ImportNode>,
node_type: ImportNodeType,
explicit: bool,
}
impl ImportNode {
pub fn new(value: String, node_type: ImportNodeType) -> Self {
Self {
value,
children: Vec::new(),
node_type,
explicit: false,
}
}
fn push(&mut self, import: &[&str]) {
if import.len() == 0 {
return;
}
match self
.children
.iter_mut()
.find(|y| y.value == import[0].to_owned())
{
Some(next_node) => {
if import.len() == 1 {
next_node.explicit = true;
}
next_node.push(&import[1..])
}
None => {
let mut next_node = ImportNode::new(import[0].to_owned(), ImportNodeType::Import);
if import.len() == 1 {
next_node.explicit = true;
}
next_node.push(&import[1..]);
self.children.push(next_node);
}
}
}
fn ensure_self(&mut self) {
if self.explicit
&& self.children.len() != 0
&& !self.children.iter().any(|child| child.value == "self")
{
self.children.insert(
0,
ImportNode::new("self".to_owned(), ImportNodeType::Import),
);
}
for child in &mut self.children {
child.ensure_self();
}
}
}
#[derive(Debug)]
struct ImportForest(Vec<ImportNode>);
impl ImportForest {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn push(&mut self, import: &Import<'_>) {
match self
.0
.iter_mut()
.find(|y| y.value == import.0[0].to_owned())
{
Some(node) => {
node.push(&import.0[1..]);
}
None => {
let mut next_node = ImportNode::new(import.0[0].to_owned(), ImportNodeType::Import);
next_node.push(&import.0[1..]);
self.0.push(next_node);
}
}
}
}
pub fn format_flat(imports: &[Import], order: Order) -> Vec<String> {
let mut res = imports.iter().fold(vec![], |mut acc, x| {
acc.push(x.0[1..].iter().fold(x.0[0].to_owned(), |acc2: String, y| {
acc2 + "::" + y.to_owned()
}));
acc
});
match order {
Order::Original => {
let mut seen = HashSet::new();
res.into_iter()
.filter(|x| seen.insert(x.clone())) // Keep only unseen items
.collect()
}
Order::Sorted => {
res.sort();
res.dedup();
res
}
}
}
pub fn format_nested(imports: &[Import], order: Order) -> Vec<String> {
let mut forest = ImportForest::new();
match order {
Order::Original => {
for x in imports {
forest.push(x);
}
}
Order::Sorted => {
let mut sorted_imports = imports.to_vec();
sorted_imports.sort();
for x in sorted_imports {
forest.push(&x);
}
}
}
let mut result = vec![];
for x in &mut forest.0 {
x.ensure_self();
}
for x in &forest.0 {
let mut q = VecDeque::from([(x, 0)]);
let mut crate_str: String = String::new();
let internal_close = ImportNode::new(String::from("},"), ImportNodeType::ClosingBrace);
let external_close = ImportNode::new(String::from("}"), ImportNodeType::ClosingBrace);
while let Some((node, level)) = q.pop_front() {
let mut new_line = String::new();
new_line.push_str(&" ".repeat(level));
match node.node_type {
ImportNodeType::ClosingBrace => {
new_line.push_str(&node.value);
new_line.push('\n');
crate_str.push_str(&new_line);
continue;
}
ImportNodeType::Import => {}
}
new_line.push_str(&node.value);
match (node.children.len(), level) {
(0, _) => new_line.push_str(",\n"),
(_, 0) => {
new_line.push_str("::{\n");
q.push_front((&external_close, 0));
}
(_, i) => {
new_line.push_str("::{\n");
q.push_front((&internal_close, i));
}
}
for next_node in node.children.iter().rev() {
q.push_front((next_node, level + 1));
}
crate_str.push_str(&new_line);
//result.push(new_line);
}
result.push(crate_str);
}
result
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20241203-1739405-1yd6zhg/solution) Finished test [unoptimized + debuginfo] target(s) in 1.34s Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165) running 20 tests test solution_test::test_flat_empty ... ok test solution_test::test_flat_multi_crate ... ok test solution_test::test_flat_original ... ok test solution_test::test_flat_original_duplicates ... ok test solution_test::test_flat_sorted ... ok test solution_test::test_flat_sorted_duplicates ... ok test solution_test::test_nested_basic ... ok test solution_test::test_nested_deep ... ok test solution_test::test_nested_empty ... ok test solution_test::test_nested_original ... ok test solution_test::test_nested_only_crate ... FAILED test solution_test::test_nested_original_2 ... ok test solution_test::test_nested_original_duplicates ... ok test solution_test::test_nested_original_multi_crate ... ok test solution_test::test_nested_original_self ... ok test solution_test::test_nested_sorted ... ok test solution_test::test_nested_sorted_2 ... ok test solution_test::test_nested_sorted_multi_crate ... ok test solution_test::test_nested_sorted_duplicates ... ok test solution_test::test_nested_sorted_self ... ok failures: ---- solution_test::test_nested_only_crate stdout ---- thread 'solution_test::test_nested_only_crate' panicked at 'assertion failed: `(left == right)` left: `["my_crate,\n"]`, right: `["my_crate\n"]`', tests/solution_test.rs:132:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failures: solution_test::test_nested_only_crate test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--test solution_test`