| 674 | } |
| 675 | |
| 676 | Expected<std::vector<std::future<Expected<void>>>> Object::serializeRecursive_( const std::filesystem::path& path, Json::Value& root, int childId, |
| 677 | MapSharedObjects* mapSharedObjects ) const |
| 678 | { |
| 679 | std::error_code ec; |
| 680 | if ( !std::filesystem::is_directory( path, ec ) ) |
| 681 | if ( !std::filesystem::create_directories( path, ec ) ) |
| 682 | return unexpected( "Cannot create directories " + utf8string( path ) ); |
| 683 | |
| 684 | std::vector<std::future<Expected<void>>> res; |
| 685 | |
| 686 | // the key must be unique among all children of same parent |
| 687 | const std::string key = composeKey( name_, childId ); |
| 688 | auto pathToSerializeModel = path / pathFromUtf8( key ); |
| 689 | |
| 690 | if ( mapSharedObjects ) |
| 691 | { |
| 692 | if ( auto it = mapSharedObjects->map.find( this ); it != mapSharedObjects->map.end() ) |
| 693 | { |
| 694 | const Object* firstSerializedObject = it->second.first; |
| 695 | // we use name of first object as name of shared model |
| 696 | const auto link = cSharedFolder / asU8String( composeKey( firstSerializedObject->name(), it->second.second ) ); |
| 697 | if ( it->first == firstSerializedObject ) |
| 698 | pathToSerializeModel = mapSharedObjects->rootFolder / link; // serialize model only one time |
| 699 | else |
| 700 | pathToSerializeModel.clear(); |
| 701 | |
| 702 | // uses forward slashes |
| 703 | root["Link"] = asString( link.generic_u8string() ); |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | if ( !pathToSerializeModel.empty() ) |
| 708 | { |
| 709 | auto model = serializeModel_( pathToSerializeModel ); |
| 710 | if ( !model.has_value() ) |
| 711 | return unexpected( model.error() ); |
| 712 | if ( model.value().valid() ) |
| 713 | res.push_back( std::move( model.value() ) ); |
| 714 | } |
| 715 | serializeFields_( root ); |
| 716 | |
| 717 | root["Key"] = key; |
| 718 | |
| 719 | if ( !children_.empty() ) |
| 720 | { |
| 721 | auto childrenPath = path / pathFromUtf8( key ); |
| 722 | auto& childrenRoot = root["Children"]; |
| 723 | for ( int i = 0; i < children_.size(); ++i ) |
| 724 | { |
| 725 | const auto& child = children_[i]; |
| 726 | if ( child->isAncillary() ) |
| 727 | continue; // consider ancillary_ objects as temporary, not requiring saving |
| 728 | auto sub = child->serializeRecursive_( childrenPath, childrenRoot[std::to_string( i )], i, mapSharedObjects ); |
| 729 | if ( !sub.has_value() ) |
| 730 | return unexpected( sub.error() ); |
| 731 | for ( auto & f : sub.value() ) |
| 732 | { |
| 733 | assert( f.valid() ); |
nothing calls this directly
no test coverage detected