1- use serde_json :: json ;
1+ use crate :: json_walk :: { WalkAction , walk_json } ;
22
33const QUALITIES : [ & str ; 6 ] = [
44 "normal" ,
@@ -9,82 +9,106 @@ const QUALITIES: [&str; 6] = [
99 "legendary" ,
1010] ;
1111
12- fn upgrade_quality ( thing : & mut serde_json:: Value ) {
13- if let Some ( quality) = thing. get_mut ( "quality" ) {
14- let s = quality. as_str ( ) . unwrap ( ) ;
15- let new_quality = QUALITIES
16- . windows ( 2 )
17- . find ( |pair| pair[ 0 ] == s)
18- . unwrap_or_else ( || panic ! ( "can't find quality {s}" ) ) [ 1 ] ;
19- * quality = json ! ( new_quality) ;
20- }
12+ fn upgrade_quality ( quality : & mut String ) {
13+ let new_quality = QUALITIES
14+ . windows ( 2 )
15+ . find ( |pair| pair[ 0 ] == quality)
16+ . unwrap_or_else ( || panic ! ( "can't find quality {quality}" ) ) [ 1 ] ;
17+ * quality = new_quality. to_owned ( ) ;
2118}
2219
23- fn upgrade_circuit_condition ( circuit_condition : & mut serde_json:: Value ) {
24- if let Some ( first_signal) = circuit_condition. get_mut ( "first_signal" ) {
25- upgrade_quality ( first_signal) ;
26- }
27- if let Some ( second_signal) = circuit_condition. get_mut ( "second_signal" ) {
28- upgrade_quality ( second_signal) ;
29- }
30- }
20+ #[ rustfmt:: skip]
21+ const UPGRADE_PATHS : & [ & [ & str ] ] = & [
22+ & [ "blueprint" , "entities" , "[]" , "filter" , "quality" ] ,
23+ & [ "blueprint" , "entities" , "[]" , "filters" , "[]" , "quality" ] ,
24+ & [ "blueprint" , "entities" , "[]" , "recipe_quality" ] ,
25+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "circuit_condition" , "first_signal" , "quality" ] ,
26+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "circuit_condition" , "second_signal" , "quality" ] ,
27+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "logistic_condition" , "first_signal" , "quality" ] ,
28+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "logistic_condition" , "second_signal" , "quality" ] ,
29+ // requester chest with sections
30+ & [ "blueprint" , "entities" , "[]" , "request_filters" , "sections" , "[]" , "filters" , "[]" , "quality" ] ,
31+ // constant combinator with sections
32+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "sections" , "sections" , "[]" , "filters" , "[]" , "quality" ] ,
33+ // decider combinator
34+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "decider_conditions" , "conditions" , "[]" , "first_signal" , "quality" ] ,
35+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "decider_conditions" , "conditions" , "[]" , "second_signal" , "quality" ] ,
36+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "decider_conditions" , "outputs" , "[]" , "signal" , "quality" ] ,
37+ // arithmetic combinator
38+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "arithmetic_conditions" , "first_signal" , "quality" ] ,
39+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "arithmetic_conditions" , "second_signal" , "quality" ] ,
40+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "arithmetic_conditions" , "output_signal" , "quality" ] ,
41+
42+ // selector combinator index signal
43+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "index_signal" , "quality" ] ,
44+ // selector combinator count signal
45+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "count_signal" , "quality" ] ,
46+ // selector combinator quality transfer static quality
47+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_source_static" , "name" ] ,
48+ // selector combinator quality filter
49+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_filter" , "quality" ] ,
50+ // selector combinator quality filter destination signal
51+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_destination_signal" , "quality" ] ,
52+
53+
54+ ] ;
55+
56+ #[ rustfmt:: skip]
57+ const IGNORE_PATHS : & [ & [ & str ] ] = & [
58+ // static quality is under quality_source_static.name, listed above
59+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_source_static" ] ,
60+ // quality filter quality is under quality_filter.quality
61+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_filter" ] ,
62+ // quality transfer destination signal (quality under quality_destination_signal.quality)
63+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_destination_signal" ] ,
64+ // quality transfer source signal (never has a quality because it picks the quality from the biggest)
65+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "quality_source_signal" ] ,
66+ ] ;
67+
68+ #[ rustfmt:: skip]
69+ const NO_UPGRADE_PATHS : & [ & [ & str ] ] = & [
70+ // Don't upgrade modules
71+ & [ "blueprint" , "entities" , "[]" , "items" , "[]" , "id" , "quality" ] ,
72+ // Don't upgrade entities
73+ & [ "blueprint" , "entities" , "[]" , "quality" ] ,
74+ // Usually icons match entities not recipes, although there's really no way to know
75+ & [ "blueprint" , "icons" , "[]" , "signal" , "quality" ] ,
76+ // Just a boolean picking between quality_source_signal and quality_source_static
77+ & [ "blueprint" , "entities" , "[]" , "control_behavior" , "select_quality_from_signal" ] ,
78+ ] ;
3179
3280pub ( crate ) fn upgrade ( mut json : serde_json:: Value ) -> serde_json:: Value {
33- let bp = json
34- . get_mut ( "blueprint" )
35- . expect ( "blueprint books not supported yet" ) ;
36- let entities = bp . get_mut ( "entities" ) . unwrap ( ) . as_array_mut ( ) . unwrap ( ) ;
37- for entity in entities {
38- if let Some ( control_behavior ) = entity . get_mut ( "control_behavior" ) {
39- if let Some ( circuit_condition ) = control_behavior . get_mut ( "circuit_condition" ) {
40- upgrade_circuit_condition ( circuit_condition ) ;
41- }
42- if let Some ( logistic_condition ) = control_behavior . get_mut ( "logistic_condition" ) {
43- upgrade_circuit_condition ( logistic_condition ) ;
44- }
45- if let Some ( serde_json :: Value :: Object ( sections ) ) = control_behavior . get_mut ( "sections" )
46- && let Some ( serde_json :: Value :: Array ( sections ) ) = sections . get_mut ( "sections ")
81+ walk_json ( & mut json , & mut |path , value| {
82+ if UPGRADE_PATHS . contains ( & path ) {
83+ let serde_json :: Value :: String ( s ) = value else {
84+ panic ! ( "can't upgrade quality at {path:?}, expected string, got {value}" ) ;
85+ } ;
86+ upgrade_quality ( s ) ;
87+ WalkAction :: Enter
88+ } else if IGNORE_PATHS . contains ( & path ) {
89+ WalkAction :: Enter
90+ } else if NO_UPGRADE_PATHS . contains ( & path ) {
91+ WalkAction :: Break
92+ } else {
93+ if let Some ( last ) = path . last ( )
94+ && last . contains ( "quality ")
4795 {
48- for section in sections {
49- if let Some ( serde_json:: Value :: Array ( filters) ) = section. get_mut ( "filters" ) {
50- for filter in filters {
51- upgrade_quality ( filter) ;
52- }
53- }
54- }
55- }
56- }
57- if let Some ( filter) = entity. get_mut ( "filter" ) {
58- upgrade_quality ( filter) ;
59- }
60- if let Some ( filters) = entity. get_mut ( "filters" ) {
61- for filter in filters. as_array_mut ( ) . unwrap ( ) {
62- upgrade_quality ( filter) ;
63- }
64- }
65- if let Some ( quality) = entity. get_mut ( "recipe_quality" ) {
66- let s = quality. as_str ( ) . unwrap ( ) ;
67- let new_quality = QUALITIES . windows ( 2 ) . find ( |pair| pair[ 0 ] == s) . unwrap ( ) [ 1 ] ;
68- * quality = json ! ( new_quality) ;
69- }
70- if let Some ( request_filters) = entity. get_mut ( "request_filters" ) {
71- if let Some ( sections) = request_filters. get_mut ( "sections" ) {
72- for section in sections. as_array_mut ( ) . unwrap ( ) {
73- if let Some ( filters) = section. get_mut ( "filters" ) {
74- for filter in filters. as_array_mut ( ) . unwrap ( ) {
75- upgrade_quality ( filter) ;
76- }
77- }
78- }
96+ panic ! (
97+ "Unhandled quality in blueprint; not sure whether we should upgrade:\n &{path:?},"
98+ ) ;
99+ } else {
100+ WalkAction :: Enter
79101 }
80102 }
81- }
103+ } ) ;
104+ // upgrade_old(json)
82105 json
83106}
84107
85108#[ cfg( test) ]
86109mod tests {
87110 use super :: * ;
111+ use serde_json:: json;
88112 use std:: str:: FromStr ;
89113
90114 macro_rules! test_bp {
@@ -774,9 +798,7 @@ mod tests {
774798 )
775799 }
776800
777- // TODO: implement arithmetic combinators
778801 #[ test]
779- #[ should_panic = "wrong signals" ]
780802 fn test_arithmetic_combinator ( ) {
781803 let bp = test_bp ! (
782804 bp: "0eNqNkc1ugzAQhN9lrzVVwk8jeJWqQsZsm5XwT9d21Aj53bvAIYdKVXxjduebMV5hWjIGJpdgWIGMdxGG9xUifTm9bJrTFmEAzZSuFhOZyng7kdPJMxQF5Gb8geFcPhSgS5QID8T+cR9dthOyLKj/UQqCj+L2bksVYnM+KbjDUNX16bWTpJkYzbHQKpCqif0yTnjVNxKAuB7kUcbzTovb4JM4pvHPpYwPAbnyjBL/nfUihUXOTnpZyZHQiBvpaStrEcTmZaiPrvAiGz6nkJ9vgIEMFDnyUymhFenxUApuyHFnd2913/Z9d2m6pr3UpfwCsbKgAQ==" ,
@@ -850,8 +872,6 @@ mod tests {
850872 }
851873
852874 #[ test]
853- // TODO: implement for decider combinators
854- #[ should_panic = "wrong qualities" ]
855875 fn test_decider_combinator ( ) {
856876 let bp = test_bp ! (
857877 bp: "0eNqdkutOwzAMhd/FvzPELmVqXwVNUdp6YKl1Qi4T1ZR3x2kngQSMjZ859Tn+juoztENC54kjNGegznKA5vkMgV7YDEVjMyI00GNHPfpVZ8eW2ETrISsg7vEdmnU+KECOFAkX//yYNKexRS8D6kqOAmeDWC2XfRK3XT8qmKBZbdb1QyVrevLYLQM7BQIZvR10i6/mRBIgrkuslm/9HBWK+vUlUEfyIepv1TrrnBBZj4Lylswg5CInFsZRdgpAwBJ1s9UbEXJW965cfHevQ0ddsQmvkwQdJ1emDfdwhYG85X+V/tF4qSx3YFN0Kf5yRn82cJP8w8RRH70dNbFEQXM0Q8BS5TaWJS0f8sxDEUcRPw9dwQl9mK+petrUu7qu9ttqu9tvcv4Afs8QFg==" ,
@@ -1061,8 +1081,55 @@ mod tests {
10611081 } )
10621082 ) ;
10631083 let upgraded = upgrade ( bp) ;
1064- // TODO implement and add assertions
1065- drop ( upgraded)
1084+ let select_combinator = jaq_one (
1085+ r#".blueprint.entities[] | select(.control_behavior.operation == "select")"# ,
1086+ upgraded. clone ( ) ,
1087+ ) ;
1088+ assert_eq ! (
1089+ jaq_one( ".control_behavior.index_signal.quality" , select_combinator) ,
1090+ json!( "legendary" ) ,
1091+ ) ;
1092+ let count_combinator = jaq_one (
1093+ r#".blueprint.entities[] | select(.control_behavior.operation == "count")"# ,
1094+ upgraded. clone ( ) ,
1095+ ) ;
1096+ assert_eq ! (
1097+ jaq_one( ".control_behavior.count_signal.quality" , count_combinator) ,
1098+ json!( "epic" ) ,
1099+ ) ;
1100+ let static_quality_transfer_combinator = jaq_one (
1101+ r#".blueprint.entities[] | select(.control_behavior.operation == "quality-transfer" and .control_behavior.quality_source_static)"# ,
1102+ upgraded. clone ( ) ,
1103+ ) ;
1104+ assert_eq ! (
1105+ jaq_one(
1106+ ".control_behavior.quality_source_static.name" ,
1107+ static_quality_transfer_combinator
1108+ ) ,
1109+ json!( "epic" ) ,
1110+ ) ;
1111+ let quality_from_signal_transfer_combinator = jaq_one (
1112+ r#".blueprint.entities[] | select(.control_behavior.operation == "quality-transfer" and .control_behavior.select_quality_from_signal == true)"# ,
1113+ upgraded. clone ( ) ,
1114+ ) ;
1115+ assert_eq ! (
1116+ jaq_one(
1117+ ".control_behavior.quality_destination_signal.quality" ,
1118+ quality_from_signal_transfer_combinator
1119+ ) ,
1120+ json!( "legendary" ) ,
1121+ ) ;
1122+ let quality_filter_combinator = jaq_one (
1123+ r#".blueprint.entities[] | select(.control_behavior.operation == "quality-filter")"# ,
1124+ upgraded. clone ( ) ,
1125+ ) ;
1126+ assert_eq ! (
1127+ jaq_one(
1128+ ".control_behavior.quality_filter.quality" ,
1129+ quality_filter_combinator
1130+ ) ,
1131+ json!( "epic" ) ,
1132+ ) ;
10661133 }
10671134
10681135 // #[test]
0 commit comments