Решение на Форматиране на импорти от Александър Глушков
Към профила на Александър Глушков
Резултати
- 18 точки от тестове
- 1 бонус точка
- 19 точки общо
- 18 успешни тест(а)
- 2 неуспешни тест(а)
Код
use std::{cell::RefCell, cmp::Ordering, rc::Rc};
#[derive(Debug, Eq, PartialEq)]
pub struct Import<'a>(pub &'a [&'a str]);
impl<'a> Clone for Import<'a> {
fn clone(&self) -> Self {
Import(self.0)
}
}
impl<'a> PartialOrd for Import<'a> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<'a> Ord for Import<'a> {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(other.0)
}
}
fn import_to_string(import: &Import) -> String {
import.0.join("::")
}
pub enum Order {
Original,
Sorted,
}
pub fn format_flat(imports: &[Import], order: Order) -> Vec<String> {
let mut result = imports.to_vec();
result.dedup_by(|a, b| a.0 == b.0);
if let Order::Sorted = order {
result.sort();
}
result.iter().map(|x| import_to_string(x)).collect()
}
type NodeRef = Rc<RefCell<Node>>;
struct Node { value: String, children: Vec<NodeRef>, self_imported: bool }
impl Node {
fn new(value: String) -> NodeRef {
Rc::new(RefCell::new(Node{value, children:vec![], self_imported: false}))
}
}
fn find_node(parent: &NodeRef, value: String) -> Option<NodeRef> {
let parent = parent.borrow();
for n in &parent.children {
let child = n.borrow();
if child.value == value {
return Some(n.clone());
}
}
None
}
fn print_from_root(root: &NodeRef) -> Vec<String> {
let mut result = Vec::new();
let root = root.borrow();
for child in &root.children {
result.push(print_crate(child, 0));
}
result
}
fn print_crate(node: &NodeRef, indent: usize) -> String {
let mut result = String::new();
let node = node.borrow();
let tabs = " ".repeat(indent);
if !node.children.is_empty() {
result.push_str(format!("{}{}::{{\n", tabs, node.value).as_str());
if node.self_imported {
result.push_str(format!("{}self,\n", " ".repeat(indent + 1)).as_str());
}
for child in &node.children {
result.push_str(print_crate(child, indent + 1).as_str());
}
if indent == 0 {
// we don't want the comma after 'main' crates
result.push_str("}\n");
}
else {
result.push_str(format!("{}}},\n", tabs).as_str());
}
}
else {
if indent == 0 {
result.push_str(format!("{}\n", node.value).as_str());
}
else {
result.push_str(format!("{}{},\n", tabs, node.value).as_str());
}
}
result
}
trait NodeRefOrd {
fn compare(&self, other: &Self) -> std::cmp::Ordering;
}
impl NodeRefOrd for NodeRef {
fn compare(&self, other: &Self) -> std::cmp::Ordering {
let self_value = self.borrow().value.clone();
let other_value = other.borrow().value.clone();
self_value.cmp(&other_value)
}
}
fn sort_tree(node: &NodeRef) {
let mut node = node.borrow_mut();
node.children.sort_by(|a,b| a.compare(b));
for child in &node.children {
sort_tree(child);
}
}
pub fn format_nested(imports: &[Import], order: Order) -> Vec<String> {
let root: NodeRef = Node::new(String::new());
let mut curr;
for import in imports {
curr = root.clone();
let import = import.0;
for (pos,&sub_imp) in import.iter().enumerate() {
let opt_node = find_node(&curr, String::from(sub_imp));
if let Some(r) = opt_node {
curr = r;
}
else {
let new_node = Node::new(String::from(sub_imp));
curr.borrow_mut().children.push(new_node.clone());
curr = new_node;
}
if pos == import.len() - 1 {
curr.borrow_mut().self_imported = true;
}
}
}
if let Order::Sorted = order {
sort_tree(&root);
}
print_from_root(&root)
}
#[test]
fn tryout_test() {
let l1: [&str; 3] = ["one", "two", "three"];
let l2: [&str; 3] = ["apple", "banana", "cherry"];
let l3: [&str; 2] = ["one", "two"];
let l4: [&str; 3] = ["one", "two", "six"];
let imports = &[Import(&l1), Import(&l2), Import(&l3), Import(&l4)];
assert_eq!(
format_nested(imports, Order::Original),
&[
concat!(
"one::{\n",
" two::{\n",
" self,\n",
" three,\n",
" six,\n",
" },\n",
"}\n",
),
concat!(
"apple::{\n",
" banana::{\n",
" cherry,\n",
" },\n",
"}\n",
),
]
);
assert_eq!(
format_nested(imports, Order::Sorted),
&[
concat!(
"apple::{\n",
" banana::{\n",
" cherry,\n",
" },\n",
"}\n",
),
concat!(
"one::{\n",
" two::{\n",
" self,\n",
" six,\n",
" three,\n",
" },\n",
"}\n",
),
]
);
}
#[test]
fn nested_tryout() {
let imports = &[
Import(&["my_crate", "b", "B1"]),
Import(&["my_crate", "c"]),
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "a"]),
Import(&["my_crate", "b"]),
];
for cr in format_nested(imports, Order::Sorted) {
println!("{}", cr);
}
}
#[test]
fn test_flat() {
let imports = &[
Import(&["my_crate", "b", "B1"]),
Import(&["my_crate", "c"]),
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "a"]),
];
assert_eq!(
format_flat(imports, Order::Sorted),
&[
"my_crate::a",
"my_crate::b::B1",
"my_crate::b::B2",
"my_crate::c",
]
);
assert_eq!(
format_flat(imports, Order::Original),
&[
"my_crate::b::B1",
"my_crate::c",
"my_crate::b::B2",
"my_crate::a",
]
);
}
#[test]
fn test_basic() {
let imports = &[
Import(&["my_crate", "a"]),
Import(&["my_crate", "b", "B1"]),
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "c"]),
];
assert_eq!(
format_flat(imports, Order::Sorted),
&[
"my_crate::a",
"my_crate::b::B1",
"my_crate::b::B2",
"my_crate::c",
]
);
assert_eq!(
format_nested(imports, Order::Sorted),
&[
concat!(
"my_crate::{\n",
" a,\n",
" b::{\n",
" B1,\n",
" B2,\n",
" },\n",
" c,\n",
"}\n",
)
]
);
}
#[test]
fn test_nested() {
let imports = &[
Import(&["my_crate", "b", "B2"]),
Import(&["my_crate", "c"]),
Import(&["my_crate", "a"]),
Import(&["my_crate", "b", "B1"]),
];
assert_eq!(
format_nested(imports, Order::Sorted),
&[
concat!(
"my_crate::{\n",
" a,\n",
" b::{\n",
" B1,\n",
" B2,\n",
" },\n",
" c,\n",
"}\n",
)
]
);
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20241203-1739405-11fxf18/solution) Finished test [unoptimized + debuginfo] target(s) in 1.17s 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_sorted ... ok test solution_test::test_flat_original_duplicates ... FAILED test solution_test::test_flat_sorted_duplicates ... FAILED test solution_test::test_nested_basic ... ok test solution_test::test_nested_empty ... ok test solution_test::test_nested_deep ... ok test solution_test::test_nested_only_crate ... ok test solution_test::test_nested_original ... ok 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_duplicates ... ok test solution_test::test_nested_sorted_multi_crate ... ok test solution_test::test_nested_sorted_self ... ok failures: ---- solution_test::test_flat_original_duplicates stdout ---- thread 'solution_test::test_flat_original_duplicates' panicked at 'assertion failed: `(left == right)` left: `["std::string::String", "std::iter::once", "std::iter", "std::iter::repeat", "std::string::String"]`, right: `["std::string::String", "std::iter::once", "std::iter", "std::iter::repeat"]`', tests/solution_test.rs:44:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- solution_test::test_flat_sorted_duplicates stdout ---- thread 'solution_test::test_flat_sorted_duplicates' panicked at 'assertion failed: `(left == right)` left: `["std::iter", "std::iter::once", "std::iter::repeat", "std::string::String", "std::string::String"]`, right: `["std::iter", "std::iter::once", "std::iter::repeat", "std::string::String"]`', tests/solution_test.rs:88:5 failures: solution_test::test_flat_original_duplicates solution_test::test_flat_sorted_duplicates test result: FAILED. 18 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass `--test solution_test`