This patch allows Python scripts to create ID Properties which reference datablocks. This functionality has been on the cards for some time: I've been expanding stub functions and removing "not implemented" comments all over the place. The absence of datablock properties "will certainly be resolved soon as the need for them is becoming obvious" said the Python Nodes release notes...last May!
I've been writing this patch in conjunction with an add-on that uses it, so the code is quite mature already.
The patch adds bpy.props.DatablockProperty and bpy.props.DatablockVectorProperty which both requires a "type" value derived from bpy.types.ID. I decided against re-using PointerProperty as it doesn't support assignment, is never None and currently only handles bpy.types.PropertyGroup objects (which are not compatible with ID).
A DatablockProperty can hold not only the assigned type but also anything derived from it. This allows the user to create a bpy.types.ID property and use it to store any sort of datablock that their script might need to deal with.
In addition to the standard update callback, DatablockProperty can have a poll callback (standard RNA) and a cast callback. cast exists because set would be self-defeating, as the whole point of ID Properties is to pass an item into C. It's called just before the value is stored and provides a chance for the Python script to interpret or switch the value, which is particularly useful when dealing with UILayout.prop_search and/or CollectionProperty objects.
One thing that the patch doesn't do is change ID user counts. We can't assume that the relevant script will be running to tell Blender what to do, so it's either on all the time or off all the time.
IMO off is the sensible choice: all ID types already have an established means to gain users, and it would be irritating if an obscure ID Prop somewhere made other IDs hang around forever.
The patch also fixes an oversight in readfile.c's test_pointer_array. It assumed that the length of pointers in the array was the same as the file in general's, but in an array which has been saved blindly by a version of Blender unaware that it held pointers it might not be. This led to a crash when saving a DatablockProperty blend in a 64-bit build, re-saving it in a 32-bit build without this patch applied, then loading it in the 64-bit build again. To fix this the function now takes an optional "items" param from which it deduces the array's actual pointer size.
Demo blend: idprop_datablock.blend